diff options
author | Chris Wren <cwren@android.com> | 2012-03-30 18:28:14 -0400 |
---|---|---|
committer | Android (Google) Code Review <android-gerrit@google.com> | 2012-04-17 09:06:21 -0700 |
commit | 3a59d6e26dbec61ede7d6f87d966698e27c91d78 (patch) | |
tree | 1991beeb07ff593a230d994d6712d8a9867bfe6f | |
parent | 8334679be1a9defb9d52217542ec0a1389c9fcae (diff) | |
download | frameworks_base-3a59d6e26dbec61ede7d6f87d966698e27c91d78.zip frameworks_base-3a59d6e26dbec61ede7d6f87d966698e27c91d78.tar.gz frameworks_base-3a59d6e26dbec61ede7d6f87d966698e27c91d78.tar.bz2 |
A layout that switches between its children based on the requested layout height.
Change-Id: I5a4e5892fbed7cab2470e458a38accbbcb05ae51
18 files changed, 1428 insertions, 0 deletions
diff --git a/core/java/com/android/internal/widget/SizeAdaptiveLayout.java b/core/java/com/android/internal/widget/SizeAdaptiveLayout.java new file mode 100644 index 0000000..adfd3dc --- /dev/null +++ b/core/java/com/android/internal/widget/SizeAdaptiveLayout.java @@ -0,0 +1,405 @@ +/* + * Copyright (C) 2012 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.internal.widget; + +import com.android.internal.R; + +import android.animation.Animator; +import android.animation.Animator.AnimatorListener; +import android.animation.AnimatorSet; +import android.animation.ObjectAnimator; +import android.content.Context; +import android.content.res.TypedArray; +import android.graphics.Color; +import android.graphics.drawable.ColorDrawable; +import android.util.AttributeSet; +import android.util.Log; +import android.view.View; +import android.view.ViewDebug; +import android.view.ViewGroup; +import android.widget.RemoteViews.RemoteView; + +/** + * A layout that switches between its children based on the requested layout height. + * Each child specifies its minimum and maximum valid height. Results are undefined + * if children specify overlapping ranges. A child may specify the maximum height + * as 'unbounded' to indicate that it is willing to be displayed arbitrarily tall. + * + * <p> + * See {@link SizeAdaptiveLayout.LayoutParams} for a full description of the + * layout parameters used by SizeAdaptiveLayout. + */ +@RemoteView +public class SizeAdaptiveLayout extends ViewGroup { + + private static final String TAG = "SizeAdaptiveLayout"; + private static final boolean DEBUG = false; + private static final long CROSSFADE_TIME = 250; + + // TypedArray indices + private static final int MIN_VALID_HEIGHT = + R.styleable.SizeAdaptiveLayout_Layout_layout_minHeight; + private static final int MAX_VALID_HEIGHT = + R.styleable.SizeAdaptiveLayout_Layout_layout_maxHeight; + + // view state + private View mActiveChild; + private View mLastActive; + + // animation state + private AnimatorSet mTransitionAnimation; + private AnimatorListener mAnimatorListener; + private ObjectAnimator mFadePanel; + private ObjectAnimator mFadeView; + private int mCanceledAnimationCount; + private View mEnteringView; + private View mLeavingView; + // View used to hide larger views under smaller ones to create a uniform crossfade + private View mModestyPanel; + private int mModestyPanelTop; + + public SizeAdaptiveLayout(Context context) { + super(context); + initialize(); + } + + public SizeAdaptiveLayout(Context context, AttributeSet attrs) { + super(context, attrs); + initialize(); + } + + public SizeAdaptiveLayout(Context context, AttributeSet attrs, int defStyle) { + super(context, attrs, defStyle); + initialize(); + } + + private void initialize() { + mModestyPanel = new View(getContext()); + // If the SizeAdaptiveLayout has a solid background, use it as a transition hint. + if (getBackground() instanceof ColorDrawable) { + mModestyPanel.setBackgroundDrawable(getBackground()); + } else { + mModestyPanel.setBackgroundColor(Color.BLACK); + } + SizeAdaptiveLayout.LayoutParams layout = + new SizeAdaptiveLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, + ViewGroup.LayoutParams.MATCH_PARENT); + mModestyPanel.setLayoutParams(layout); + addView(mModestyPanel); + mFadePanel = ObjectAnimator.ofFloat(mModestyPanel, "alpha", 0f); + mFadeView = ObjectAnimator.ofFloat(null, "alpha", 0f); + mAnimatorListener = new BringToFrontOnEnd(); + mTransitionAnimation = new AnimatorSet(); + mTransitionAnimation.play(mFadeView).with(mFadePanel); + mTransitionAnimation.setDuration(CROSSFADE_TIME); + mTransitionAnimation.addListener(mAnimatorListener); + } + + /** + * Visible for testing + * @hide + */ + public Animator getTransitionAnimation() { + return mTransitionAnimation; + } + + /** + * Visible for testing + * @hide + */ + public View getModestyPanel() { + return mModestyPanel; + } + + @Override + public void onAttachedToWindow() { + mLastActive = null; + // make sure all views start off invisible. + for (int i = 0; i < getChildCount(); i++) { + getChildAt(i).setVisibility(View.GONE); + } + } + + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + if (DEBUG) Log.d(TAG, this + " measure spec: " + + MeasureSpec.toString(heightMeasureSpec)); + View model = selectActiveChild(heightMeasureSpec); + SizeAdaptiveLayout.LayoutParams lp = + (SizeAdaptiveLayout.LayoutParams) model.getLayoutParams(); + if (DEBUG) Log.d(TAG, "active min: " + lp.minHeight + " max: " + lp.maxHeight); + measureChild(model, widthMeasureSpec, heightMeasureSpec); + int childHeight = model.getMeasuredHeight(); + int childWidth = model.getMeasuredHeight(); + int childState = combineMeasuredStates(0, model.getMeasuredState()); + if (DEBUG) Log.d(TAG, "measured child at: " + childHeight); + int resolvedWidth = resolveSizeAndState(childWidth, widthMeasureSpec, childState); + int resolvedheight = resolveSizeAndState(childHeight, heightMeasureSpec, childState); + setMeasuredDimension(resolvedWidth, resolvedheight); + if (DEBUG) Log.d(TAG, "resolved to: " + resolvedheight); + } + + //TODO extend to width and height + private View selectActiveChild(int heightMeasureSpec) { + final int heightMode = MeasureSpec.getMode(heightMeasureSpec); + final int heightSize = MeasureSpec.getSize(heightMeasureSpec); + + View unboundedView = null; + View tallestView = null; + int tallestViewSize = 0; + View smallestView = null; + int smallestViewSize = Integer.MAX_VALUE; + for (int i = 0; i < getChildCount(); i++) { + View child = getChildAt(i); + if (child != mModestyPanel) { + SizeAdaptiveLayout.LayoutParams lp = + (SizeAdaptiveLayout.LayoutParams) child.getLayoutParams(); + if (DEBUG) Log.d(TAG, "looking at " + i + + " with min: " + lp.minHeight + + " max: " + lp.maxHeight); + if (lp.maxHeight == SizeAdaptiveLayout.LayoutParams.UNBOUNDED && + unboundedView == null) { + unboundedView = child; + } + if (lp.maxHeight > tallestViewSize) { + tallestViewSize = lp.maxHeight; + tallestView = child; + } + if (lp.minHeight < smallestViewSize) { + smallestViewSize = lp.minHeight; + smallestView = child; + } + if (heightMode != MeasureSpec.UNSPECIFIED && + heightSize >= lp.minHeight && heightSize <= lp.maxHeight) { + if (DEBUG) Log.d(TAG, " found exact match, finishing early"); + return child; + } + } + } + if (unboundedView != null) { + tallestView = unboundedView; + } + if (heightMode == MeasureSpec.UNSPECIFIED) { + return tallestView; + } + if (heightSize > tallestViewSize) { + return tallestView; + } + return smallestView; + } + + @Override + protected void onLayout(boolean changed, int left, int top, int right, int bottom) { + if (DEBUG) Log.d(TAG, this + " onlayout height: " + (bottom - top)); + mLastActive = mActiveChild; + int measureSpec = View.MeasureSpec.makeMeasureSpec(bottom - top, + View.MeasureSpec.EXACTLY); + mActiveChild = selectActiveChild(measureSpec); + mActiveChild.setVisibility(View.VISIBLE); + + if (mLastActive != mActiveChild && mLastActive != null) { + if (DEBUG) Log.d(TAG, this + " changed children from: " + mLastActive + + " to: " + mActiveChild); + + mEnteringView = mActiveChild; + mLeavingView = mLastActive; + + mEnteringView.setAlpha(1f); + + mModestyPanel.setAlpha(1f); + mModestyPanel.bringToFront(); + mModestyPanelTop = mLeavingView.getHeight(); + mModestyPanel.setVisibility(View.VISIBLE); + // TODO: mModestyPanel background should be compatible with mLeavingView + + mLeavingView.bringToFront(); + + if (mTransitionAnimation.isRunning()) { + mTransitionAnimation.cancel(); + } + mFadeView.setTarget(mLeavingView); + mFadeView.setFloatValues(0f); + mFadePanel.setFloatValues(0f); + mTransitionAnimation.setupStartValues(); + mTransitionAnimation.start(); + } + final int childWidth = mActiveChild.getMeasuredWidth(); + final int childHeight = mActiveChild.getMeasuredHeight(); + // TODO investigate setting LAYER_TYPE_HARDWARE on mLastActive + mActiveChild.layout(0, 0, 0 + childWidth, 0 + childHeight); + + if (DEBUG) Log.d(TAG, "got modesty offset of " + mModestyPanelTop); + mModestyPanel.layout(0, mModestyPanelTop, 0 + childWidth, mModestyPanelTop + childHeight); + } + + @Override + public LayoutParams generateLayoutParams(AttributeSet attrs) { + if (DEBUG) Log.d(TAG, "generate layout from attrs"); + return new SizeAdaptiveLayout.LayoutParams(getContext(), attrs); + } + + @Override + protected LayoutParams generateLayoutParams(ViewGroup.LayoutParams p) { + if (DEBUG) Log.d(TAG, "generate default layout from viewgroup"); + return new SizeAdaptiveLayout.LayoutParams(p); + } + + @Override + protected LayoutParams generateDefaultLayoutParams() { + if (DEBUG) Log.d(TAG, "generate default layout from null"); + return new SizeAdaptiveLayout.LayoutParams(); + } + + @Override + protected boolean checkLayoutParams(ViewGroup.LayoutParams p) { + return p instanceof SizeAdaptiveLayout.LayoutParams; + } + + /** + * Per-child layout information associated with ViewSizeAdaptiveLayout. + * + * TODO extend to width and height + * + * @attr ref android.R.styleable#SizeAdaptiveLayout_Layout_layout_minHeight + * @attr ref android.R.styleable#SizeAdaptiveLayout_Layout_layout_maxHeight + */ + public static class LayoutParams extends ViewGroup.LayoutParams { + + /** + * Indicates the minimum valid height for the child. + */ + @ViewDebug.ExportedProperty(category = "layout") + public int minHeight; + + /** + * Indicates the maximum valid height for the child. + */ + @ViewDebug.ExportedProperty(category = "layout") + public int maxHeight; + + /** + * Constant value for maxHeight that indicates there is not maximum height. + */ + public static final int UNBOUNDED = -1; + + /** + * {@inheritDoc} + */ + public LayoutParams(Context c, AttributeSet attrs) { + super(c, attrs); + if (DEBUG) { + Log.d(TAG, "construct layout from attrs"); + for (int i = 0; i < attrs.getAttributeCount(); i++) { + Log.d(TAG, " " + attrs.getAttributeName(i) + " = " + + attrs.getAttributeValue(i)); + } + } + TypedArray a = + c.obtainStyledAttributes(attrs, + R.styleable.SizeAdaptiveLayout_Layout); + + minHeight = a.getDimensionPixelSize(MIN_VALID_HEIGHT, 0); + if (DEBUG) Log.d(TAG, "got minHeight of: " + minHeight); + + try { + maxHeight = a.getLayoutDimension(MAX_VALID_HEIGHT, UNBOUNDED); + if (DEBUG) Log.d(TAG, "got maxHeight of: " + maxHeight); + } catch (Exception e) { + if (DEBUG) Log.d(TAG, "caught exception looking for maxValidHeight " + e); + } + + a.recycle(); + } + + /** + * Creates a new set of layout parameters with the specified width, height + * and valid height bounds. + * + * @param width the width, either {@link #MATCH_PARENT}, + * {@link #WRAP_CONTENT} or a fixed size in pixels + * @param height the height, either {@link #MATCH_PARENT}, + * {@link #WRAP_CONTENT} or a fixed size in pixels + * @param minHeight the minimum height of this child + * @param maxHeight the maximum height of this child + * or {@link #UNBOUNDED} if the child can grow forever + */ + public LayoutParams(int width, int height, int minHeight, int maxHeight) { + super(width, height); + this.minHeight = minHeight; + this.maxHeight = maxHeight; + } + + /** + * {@inheritDoc} + */ + public LayoutParams(int width, int height) { + this(width, height, UNBOUNDED, UNBOUNDED); + } + + /** + * Constructs a new LayoutParams with default values as defined in {@link LayoutParams}. + */ + public LayoutParams() { + this(MeasureSpec.UNSPECIFIED, MeasureSpec.UNSPECIFIED); + } + + /** + * {@inheritDoc} + */ + public LayoutParams(ViewGroup.LayoutParams p) { + super(p); + minHeight = UNBOUNDED; + maxHeight = UNBOUNDED; + } + + public String debug(String output) { + return output + "SizeAdaptiveLayout.LayoutParams={" + + ", max=" + maxHeight + + ", max=" + minHeight + "}"; + } + } + + class BringToFrontOnEnd implements AnimatorListener { + @Override + public void onAnimationEnd(Animator animation) { + if (mCanceledAnimationCount == 0) { + mLeavingView.setVisibility(View.GONE); + mModestyPanel.setVisibility(View.GONE); + mEnteringView.bringToFront(); + mEnteringView = null; + mLeavingView = null; + } else { + mCanceledAnimationCount--; + } + } + + @Override + public void onAnimationCancel(Animator animation) { + mCanceledAnimationCount++; + } + + @Override + public void onAnimationRepeat(Animator animation) { + if (DEBUG) Log.d(TAG, "fade animation repeated: should never happen."); + assert(false); + } + + @Override + public void onAnimationStart(Animator animation) { + } + } +} diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml index 600a834..6f489d4 100755 --- a/core/res/res/values/attrs.xml +++ b/core/res/res/values/attrs.xml @@ -5380,6 +5380,21 @@ </declare-styleable> <!-- =============================== --> + <!-- SizeAdaptiveLayout class attributes --> + <!-- =============================== --> + <eat-comment /> + <declare-styleable name="SizeAdaptiveLayout_Layout"> + <!-- The maximum valid height for this item. --> + <attr name="layout_maxHeight" format="dimension"> + <!-- Indicates that the view may be resized arbitrarily large. --> + <enum name="unbounded" value="-1" /> + </attr> + <!-- The minimum valid height for this item. --> + <attr name="layout_minHeight" format="dimension" /> + </declare-styleable> + <declare-styleable name="SizeAdaptiveLayout" /> + + <!-- =============================== --> <!-- LockPatternView class attributes --> <!-- =============================== --> <eat-comment /> diff --git a/core/tests/coretests/res/drawable/abe.jpg b/core/tests/coretests/res/drawable/abe.jpg Binary files differnew file mode 100644 index 0000000..1f978a9 --- /dev/null +++ b/core/tests/coretests/res/drawable/abe.jpg diff --git a/core/tests/coretests/res/drawable/gettysburg.png b/core/tests/coretests/res/drawable/gettysburg.png Binary files differnew file mode 100644 index 0000000..7a2d596 --- /dev/null +++ b/core/tests/coretests/res/drawable/gettysburg.png diff --git a/core/tests/coretests/res/layout/size_adaptive.xml b/core/tests/coretests/res/layout/size_adaptive.xml new file mode 100644 index 0000000..03d0574 --- /dev/null +++ b/core/tests/coretests/res/layout/size_adaptive.xml @@ -0,0 +1,40 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Copyright (C) 2012 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> +<com.android.internal.widget.SizeAdaptiveLayout + xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:internal="http://schemas.android.com/apk/prv/res/android" + android:id="@+id/multi1" + android:layout_width="match_parent" + android:layout_height="64dp" > + + <include + android:id="@+id/one_u" + layout="@layout/size_adaptive_one_u" + android:layout_width="fill_parent" + android:layout_height="64dp" + internal:layout_minHeight="64dp" + internal:layout_maxHeight="64dp" + /> + + <include + android:id="@+id/four_u" + layout="@layout/size_adaptive_four_u" + android:layout_width="fill_parent" + android:layout_height="wrap_content" + internal:layout_minHeight="65dp" + internal:layout_maxHeight="unbounded"/> + +</com.android.internal.widget.SizeAdaptiveLayout> diff --git a/core/tests/coretests/res/layout/size_adaptive_color.xml b/core/tests/coretests/res/layout/size_adaptive_color.xml new file mode 100644 index 0000000..cdb7a59 --- /dev/null +++ b/core/tests/coretests/res/layout/size_adaptive_color.xml @@ -0,0 +1,41 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Copyright (C) 2012 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> +<com.android.internal.widget.SizeAdaptiveLayout + xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:internal="http://schemas.android.com/apk/prv/res/android" + android:background="#ffffff" + android:id="@+id/multi1" + android:layout_width="match_parent" + android:layout_height="64dp" > + + <include + android:id="@+id/one_u" + layout="@layout/size_adaptive_one_u" + android:layout_width="fill_parent" + android:layout_height="64dp" + internal:layout_minHeight="64dp" + internal:layout_maxHeight="64dp" + /> + + <include + android:id="@+id/four_u" + layout="@layout/size_adaptive_four_u" + android:layout_width="fill_parent" + android:layout_height="wrap_content" + internal:layout_minHeight="65dp" + internal:layout_maxHeight="unbounded"/> + +</com.android.internal.widget.SizeAdaptiveLayout> diff --git a/core/tests/coretests/res/layout/size_adaptive_four_u.xml b/core/tests/coretests/res/layout/size_adaptive_four_u.xml new file mode 100644 index 0000000..232b921 --- /dev/null +++ b/core/tests/coretests/res/layout/size_adaptive_four_u.xml @@ -0,0 +1,68 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Copyright (C) 2012 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> +<GridLayout xmlns:android="http://schemas.android.com/apk/res/android" + android:id="@+id/gridLayout4" + android:layout_width="match_parent" + android:layout_height="256dp" + android:background="#000000" + android:columnCount="2" + android:padding="1dp" > + + <ImageView + android:id="@+id/actor" + android:layout_width="62dp" + android:layout_height="62dp" + android:layout_row="0" + android:layout_column="0" + android:layout_rowSpan="2" + android:contentDescription="@string/actor" + android:src="@drawable/abe" /> + + <TextView + android:layout_width="0dp" + android:id="@+id/name" + android:layout_row="0" + android:layout_column="1" + android:layout_gravity="fill_horizontal" + android:padding="3dp" + android:text="@string/actor" + android:textColor="#ffffff" + android:textStyle="bold" /> + + <ImageView + android:layout_width="0dp" + android:layout_height="wrap_content" + android:layout_row="1" + android:layout_column="1" + android:layout_gravity="fill_horizontal" + android:padding="5dp" + android:adjustViewBounds="true" + android:background="#555555" + android:scaleType="centerCrop" + android:src="@drawable/gettysburg" + android:contentDescription="@string/caption" /> + + <TextView + android:layout_width="0dp" + android:id="@+id/note" + android:layout_row="2" + android:layout_column="1" + android:layout_gravity="fill_horizontal" + android:padding="3dp" + android:singleLine="true" + android:text="@string/first" + android:textColor="#ffffff" /> +</GridLayout> diff --git a/core/tests/coretests/res/layout/size_adaptive_four_u_text.xml b/core/tests/coretests/res/layout/size_adaptive_four_u_text.xml new file mode 100644 index 0000000..93a10de --- /dev/null +++ b/core/tests/coretests/res/layout/size_adaptive_four_u_text.xml @@ -0,0 +1,59 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Copyright (C) 2012 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> +<GridLayout xmlns:android="http://schemas.android.com/apk/res/android" + android:id="@+id/gridLayout4" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:background="#000000" + android:columnCount="2" + android:padding="1dp" + android:orientation="horizontal" > + + <ImageView + android:id="@+id/actor" + android:layout_width="62dp" + android:layout_height="62dp" + android:layout_row="0" + android:layout_column="0" + android:layout_rowSpan="2" + android:contentDescription="@string/actor" + android:src="@drawable/abe" /> + + <TextView + android:layout_width="0dp" + android:id="@+id/name" + android:layout_row="0" + android:layout_column="1" + android:layout_gravity="fill_horizontal" + android:padding="3dp" + android:text="@string/actor" + android:textColor="#ffffff" + android:textStyle="bold" /> + + <TextView + android:id="@+id/note" + android:layout_width="0dp" + android:layout_height="wrap_content" + android:layout_column="1" + android:layout_gravity="fill_horizontal" + android:layout_marginTop="5dp" + android:layout_row="1" + android:padding="3dp" + android:singleLine="false" + android:text="@string/first" + android:textColor="#ffffff" /> + + </GridLayout> diff --git a/core/tests/coretests/res/layout/size_adaptive_gappy.xml b/core/tests/coretests/res/layout/size_adaptive_gappy.xml new file mode 100644 index 0000000..d5e3b41 --- /dev/null +++ b/core/tests/coretests/res/layout/size_adaptive_gappy.xml @@ -0,0 +1,40 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Copyright (C) 2012 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> +<com.android.internal.widget.SizeAdaptiveLayout + xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:internal="http://schemas.android.com/apk/prv/res/android" + android:id="@+id/multi_with_gap" + android:layout_width="match_parent" + android:layout_height="64dp" > + + <include + android:id="@+id/one_u" + layout="@layout/size_adaptive_one_u" + android:layout_width="fill_parent" + android:layout_height="64dp" + internal:layout_minHeight="64dp" + internal:layout_maxHeight="64dp" + /> + + <include + android:id="@+id/four_u" + layout="@layout/size_adaptive_four_u" + android:layout_width="fill_parent" + android:layout_height="256dp" + internal:layout_minHeight="128dp" + internal:layout_maxHeight="unbounded"/> + +</com.android.internal.widget.SizeAdaptiveLayout> diff --git a/core/tests/coretests/res/layout/size_adaptive_large_only.xml b/core/tests/coretests/res/layout/size_adaptive_large_only.xml new file mode 100644 index 0000000..cf58265 --- /dev/null +++ b/core/tests/coretests/res/layout/size_adaptive_large_only.xml @@ -0,0 +1,31 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Copyright (C) 2012 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> +<com.android.internal.widget.SizeAdaptiveLayout + xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:internal="http://schemas.android.com/apk/prv/res/android" + android:id="@+id/large_only_multi" + android:layout_width="match_parent" + android:layout_height="64dp" > + + <include + android:id="@+id/four_u" + layout="@layout/size_adaptive_four_u" + android:layout_width="fill_parent" + android:layout_height="256dp" + internal:layout_minHeight="65dp" + internal:layout_maxHeight="unbounded"/> + +</com.android.internal.widget.SizeAdaptiveLayout> diff --git a/core/tests/coretests/res/layout/size_adaptive_one_u.xml b/core/tests/coretests/res/layout/size_adaptive_one_u.xml new file mode 100644 index 0000000..b6fe4a0 --- /dev/null +++ b/core/tests/coretests/res/layout/size_adaptive_one_u.xml @@ -0,0 +1,66 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Copyright (C) 2012 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> +<GridLayout xmlns:android="http://schemas.android.com/apk/res/android" + android:id="@+id/gridLayout1" + android:layout_width="match_parent" + android:layout_height="64dp" + android:background="#000000" + android:columnCount="3" + android:padding="1dp" + android:rowCount="2" > + + <ImageView + android:id="@+id/actor" + android:layout_width="62dp" + android:layout_height="62dp" + android:layout_column="0" + android:layout_row="0" + android:layout_rowSpan="2" + android:contentDescription="@string/actor" + android:src="@drawable/abe" /> + + <TextView + android:id="@+id/name" + android:layout_gravity="fill" + android:padding="3dp" + android:text="@string/actor" + android:textColor="#ffffff" + android:textStyle="bold" /> + + <ImageView + android:layout_width="62dp" + android:layout_height="62dp" + android:layout_gravity="fill_vertical" + android:layout_rowSpan="2" + android:adjustViewBounds="true" + android:background="#555555" + android:padding="2dp" + android:scaleType="fitXY" + android:src="@drawable/gettysburg" + android:contentDescription="@string/caption" /> + + <TextView + android:id="@+id/note" + android:layout_width="0dp" + android:layout_height="0dp" + android:layout_gravity="fill" + android:layout_marginTop="5dp" + android:padding="3dp" + android:singleLine="true" + android:text="@string/first" + android:textColor="#ffffff" /> + +</GridLayout> diff --git a/core/tests/coretests/res/layout/size_adaptive_one_u_text.xml b/core/tests/coretests/res/layout/size_adaptive_one_u_text.xml new file mode 100644 index 0000000..df54eb6 --- /dev/null +++ b/core/tests/coretests/res/layout/size_adaptive_one_u_text.xml @@ -0,0 +1,54 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Copyright (C) 2012 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> +<GridLayout xmlns:android="http://schemas.android.com/apk/res/android" + android:id="@+id/gridLayout1" + android:layout_width="match_parent" + android:layout_height="64dp" + android:background="#000000" + android:columnCount="2" + android:padding="1dp" + android:rowCount="2" > + + <ImageView + android:id="@+id/actor" + android:layout_width="62dp" + android:layout_height="62dp" + android:layout_column="0" + android:layout_row="0" + android:layout_rowSpan="2" + android:contentDescription="@string/actor" + android:src="@drawable/abe" /> + + <TextView + android:id="@+id/name" + android:layout_gravity="fill" + android:padding="3dp" + android:text="@string/actor" + android:textColor="#ffffff" + android:textStyle="bold" /> + + <TextView + android:id="@+id/note" + android:layout_width="0dp" + android:layout_height="0dp" + android:layout_gravity="fill" + android:layout_marginTop="5dp" + android:padding="3dp" + android:singleLine="true" + android:text="@string/first" + android:textColor="#ffffff" /> + +</GridLayout> diff --git a/core/tests/coretests/res/layout/size_adaptive_overlapping.xml b/core/tests/coretests/res/layout/size_adaptive_overlapping.xml new file mode 100644 index 0000000..4abe8b0 --- /dev/null +++ b/core/tests/coretests/res/layout/size_adaptive_overlapping.xml @@ -0,0 +1,40 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Copyright (C) 2012 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> +<com.android.internal.widget.SizeAdaptiveLayout + xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:internal="http://schemas.android.com/apk/prv/res/android" + android:id="@+id/multi_with_overlap" + android:layout_width="match_parent" + android:layout_height="64dp" > + + <include + android:id="@+id/one_u" + layout="@layout/size_adaptive_one_u" + android:layout_width="fill_parent" + android:layout_height="64dp" + internal:layout_minHeight="64dp" + internal:layout_maxHeight="64dp" + /> + + <include + android:id="@+id/four_u" + layout="@layout/size_adaptive_four_u" + android:layout_width="fill_parent" + android:layout_height="256dp" + internal:layout_minHeight="64dp" + internal:layout_maxHeight="256dp"/> + +</com.android.internal.widget.SizeAdaptiveLayout> diff --git a/core/tests/coretests/res/layout/size_adaptive_singleton.xml b/core/tests/coretests/res/layout/size_adaptive_singleton.xml new file mode 100644 index 0000000..eba387f --- /dev/null +++ b/core/tests/coretests/res/layout/size_adaptive_singleton.xml @@ -0,0 +1,31 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Copyright (C) 2012 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> +<com.android.internal.widget.SizeAdaptiveLayout + xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:internal="http://schemas.android.com/apk/prv/res/android" + android:layout_width="match_parent" + android:layout_height="64dp" > + + <include + android:id="@+id/one_u" + layout="@layout/size_adaptive_one_u_text" + android:layout_width="fill_parent" + android:layout_height="64dp" + internal:layout_minHeight="64dp" + internal:layout_maxHeight="64dp" + /> + +</com.android.internal.widget.SizeAdaptiveLayout> diff --git a/core/tests/coretests/res/layout/size_adaptive_text.xml b/core/tests/coretests/res/layout/size_adaptive_text.xml new file mode 100644 index 0000000..a9f0ba9 --- /dev/null +++ b/core/tests/coretests/res/layout/size_adaptive_text.xml @@ -0,0 +1,40 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Copyright (C) 2012 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> +<com.android.internal.widget.SizeAdaptiveLayout + xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:internal="http://schemas.android.com/apk/prv/res/android" + android:id="@+id/multi1" + android:layout_width="match_parent" + android:layout_height="64dp" > + + <include + android:id="@+id/one_u" + layout="@layout/size_adaptive_one_u_text" + android:layout_width="fill_parent" + android:layout_height="64dp" + internal:layout_minHeight="64dp" + internal:layout_maxHeight="64dp" + /> + + <include + android:id="@+id/four_u" + layout="@layout/size_adaptive_four_u_text" + android:layout_width="fill_parent" + android:layout_height="wrap_content" + internal:layout_minHeight="65dp" + internal:layout_maxHeight="unbounded"/> + +</com.android.internal.widget.SizeAdaptiveLayout> diff --git a/core/tests/coretests/res/layout/size_adaptive_three_way.xml b/core/tests/coretests/res/layout/size_adaptive_three_way.xml new file mode 100644 index 0000000..1eb5396 --- /dev/null +++ b/core/tests/coretests/res/layout/size_adaptive_three_way.xml @@ -0,0 +1,48 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Copyright (C) 2012 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> +<com.android.internal.widget.SizeAdaptiveLayout + xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:internal="http://schemas.android.com/apk/prv/res/android" + android:id="@+id/three_way_multi" + android:layout_width="match_parent" + android:layout_height="64dp" > + + <include + android:id="@+id/one_u" + layout="@layout/size_adaptive_one_u" + android:layout_width="fill_parent" + android:layout_height="64dp" + internal:layout_minHeight="64dp" + internal:layout_maxHeight="64dp" + /> + + <include + android:id="@+id/two_u" + layout="@layout/size_adaptive_four_u" + android:layout_width="fill_parent" + android:layout_height="128dp" + internal:layout_minHeight="65dp" + internal:layout_maxHeight="128dp"/> + + <include + android:id="@+id/four_u" + layout="@layout/size_adaptive_four_u" + android:layout_width="fill_parent" + android:layout_height="256dp" + internal:layout_minHeight="129dp" + internal:layout_maxHeight="unbounded"/> + +</com.android.internal.widget.SizeAdaptiveLayout> diff --git a/core/tests/coretests/res/values/strings.xml b/core/tests/coretests/res/values/strings.xml index 71f3520..ce0d9a2 100644 --- a/core/tests/coretests/res/values/strings.xml +++ b/core/tests/coretests/res/values/strings.xml @@ -131,4 +131,8 @@ <string name="textview_hebrew_text">םמab?!</string> + <!-- SizeAdaptiveLayout --> + <string name="first">Four score and seven years ago our fathers brought forth on this continent, a new nation, conceived in Liberty, and dedicated to the proposition that all men are created equal.</string> + <string name="actor">Abe Lincoln</string> + <string name="caption">Lincoln adressing the crowd at Gettysburgh</string> </resources> diff --git a/core/tests/coretests/src/com/android/internal/widget/SizeAdaptiveLayoutTest.java b/core/tests/coretests/src/com/android/internal/widget/SizeAdaptiveLayoutTest.java new file mode 100644 index 0000000..fc83e4a --- /dev/null +++ b/core/tests/coretests/src/com/android/internal/widget/SizeAdaptiveLayoutTest.java @@ -0,0 +1,446 @@ +/* + * Copyright (C) 2012 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.internal.widget; + +import com.android.frameworks.coretests.R; + +import android.content.Context; +import android.graphics.drawable.ColorDrawable; +import android.test.AndroidTestCase; +import android.test.suitebuilder.annotation.SmallTest; +import android.view.LayoutInflater; +import android.view.View; + +import com.android.internal.widget.SizeAdaptiveLayout; + + +public class SizeAdaptiveLayoutTest extends AndroidTestCase { + + private LayoutInflater mInflater; + private int mOneU; + private int mFourU; + private SizeAdaptiveLayout mSizeAdaptiveLayout; + private View mSmallView; + private View mMediumView; + private View mLargeView; + + @Override + protected void setUp() throws Exception { + super.setUp(); + + // inflate the layout + final Context context = getContext(); + mInflater = LayoutInflater.from(context); + mOneU = 64; + mFourU = 4 * mOneU; + } + + private void inflate(int resource){ + mSizeAdaptiveLayout = (SizeAdaptiveLayout) mInflater.inflate(resource, null); + mSizeAdaptiveLayout.onAttachedToWindow(); + + mSmallView = mSizeAdaptiveLayout.findViewById(R.id.one_u); + mMediumView = mSizeAdaptiveLayout.findViewById(R.id.two_u); + mLargeView = mSizeAdaptiveLayout.findViewById(R.id.four_u); + } + + /** + * The name 'test preconditions' is a convention to signal that if this + * test doesn't pass, the test case was not set up properly and it might + * explain any and all failures in other tests. This is not guaranteed + * to run before other tests, as junit uses reflection to find the tests. + */ + @SmallTest + public void testPreconditions() { + assertNotNull(mInflater); + + inflate(R.layout.size_adaptive); + assertNotNull(mSizeAdaptiveLayout); + assertNotNull(mSmallView); + assertNotNull(mLargeView); + } + + @SmallTest + public void testOpenLarge() { + inflate(R.layout.size_adaptive); + SizeAdaptiveLayout.LayoutParams lp = + (SizeAdaptiveLayout.LayoutParams) mLargeView.getLayoutParams(); + int height = (int) lp.minHeight + 10; + + measureAndLayout(height); + + assertEquals("4U should be visible", + View.VISIBLE, + mLargeView.getVisibility()); + assertEquals("1U should be gone", + View.GONE, + mSmallView.getVisibility()); + } + + @SmallTest + public void testOpenSmall() { + inflate(R.layout.size_adaptive); + SizeAdaptiveLayout.LayoutParams lp = + (SizeAdaptiveLayout.LayoutParams) mSmallView.getLayoutParams(); + int height = (int) lp.minHeight; + + measureAndLayout(height); + + assertEquals("1U should be visible", + View.VISIBLE, + mSmallView.getVisibility()); + assertEquals("4U should be gone", + View.GONE, + mLargeView.getVisibility()); + } + + @SmallTest + public void testOpenTooSmall() { + inflate(R.layout.size_adaptive); + SizeAdaptiveLayout.LayoutParams lp = + (SizeAdaptiveLayout.LayoutParams) mSmallView.getLayoutParams(); + int height = (int) lp.minHeight - 10; + + measureAndLayout(height); + + assertEquals("1U should be visible", + View.VISIBLE, + mSmallView.getVisibility()); + assertEquals("4U should be gone", + View.GONE, + mLargeView.getVisibility()); + } + + @SmallTest + public void testOpenTooBig() { + inflate(R.layout.size_adaptive); + SizeAdaptiveLayout.LayoutParams lp = + (SizeAdaptiveLayout.LayoutParams) mLargeView.getLayoutParams(); + lp.maxHeight = 500; + mLargeView.setLayoutParams(lp); + int height = (int) (lp.minHeight + 10); + + measureAndLayout(height); + + assertEquals("4U should be visible", + View.VISIBLE, + mLargeView.getVisibility()); + assertEquals("1U should be gone", + View.GONE, + mSmallView.getVisibility()); + } + + @SmallTest + public void testOpenWrapContent() { + inflate(R.layout.size_adaptive_text); + SizeAdaptiveLayout.LayoutParams lp = + (SizeAdaptiveLayout.LayoutParams) mLargeView.getLayoutParams(); + int height = (int) lp.minHeight + 10; + + // manually measure it, and lay it out + int measureSpec = View.MeasureSpec.makeMeasureSpec(height, View.MeasureSpec.AT_MOST); + mSizeAdaptiveLayout.measure(500, measureSpec); + assertTrue("should not be forced to 4U", + mSizeAdaptiveLayout.getMeasuredHeight() < mFourU); + } + + @SmallTest + public void testOpenOneUOnlySmall() { + inflate(R.layout.size_adaptive_singleton); + assertNull("largeView should be NULL in the singleton layout", mLargeView); + + SizeAdaptiveLayout.LayoutParams lp = + (SizeAdaptiveLayout.LayoutParams) mSmallView.getLayoutParams(); + int height = (int) lp.minHeight - 10; + + measureAndLayout(height); + + assertEquals("1U should be visible", + View.VISIBLE, + mSmallView.getVisibility()); + } + + @SmallTest + public void testOpenOneUOnlyLarge() { + inflate(R.layout.size_adaptive_singleton); + assertNull("largeView should be NULL in the singleton layout", mLargeView); + + SizeAdaptiveLayout.LayoutParams lp = + (SizeAdaptiveLayout.LayoutParams) mSmallView.getLayoutParams(); + int height = (int) lp.maxHeight + 10; + + measureAndLayout(height); + + assertEquals("1U should be visible", + View.VISIBLE, + mSmallView.getVisibility()); + } + + @SmallTest + public void testOpenOneUOnlyJustRight() { + inflate(R.layout.size_adaptive_singleton); + assertNull("largeView should be NULL in the singleton layout", mLargeView); + + SizeAdaptiveLayout.LayoutParams lp = + (SizeAdaptiveLayout.LayoutParams) mSmallView.getLayoutParams(); + int height = (int) lp.minHeight; + + measureAndLayout(height); + + assertEquals("1U should be visible", + View.VISIBLE, + mSmallView.getVisibility()); + } + + @SmallTest + public void testOpenFourUOnlySmall() { + inflate(R.layout.size_adaptive_large_only); + assertNull("smallView should be NULL in the singleton layout", mSmallView); + + SizeAdaptiveLayout.LayoutParams lp = + (SizeAdaptiveLayout.LayoutParams) mLargeView.getLayoutParams(); + int height = (int) lp.minHeight - 10; + + measureAndLayout(height); + + assertEquals("4U should be visible", + View.VISIBLE, + mLargeView.getVisibility()); + } + + @SmallTest + public void testOpenFourUOnlyLarge() { + inflate(R.layout.size_adaptive_large_only); + assertNull("smallView should be NULL in the singleton layout", mSmallView); + + SizeAdaptiveLayout.LayoutParams lp = + (SizeAdaptiveLayout.LayoutParams) mLargeView.getLayoutParams(); + int height = (int) lp.maxHeight + 10; + + measureAndLayout(height); + + assertEquals("4U should be visible", + View.VISIBLE, + mLargeView.getVisibility()); + } + + @SmallTest + public void testOpenFourUOnlyJustRight() { + inflate(R.layout.size_adaptive_large_only); + assertNull("smallView should be NULL in the singleton layout", mSmallView); + + SizeAdaptiveLayout.LayoutParams lp = + (SizeAdaptiveLayout.LayoutParams) mLargeView.getLayoutParams(); + int height = (int) lp.minHeight; + + measureAndLayout(height); + + assertEquals("4U should be visible", + View.VISIBLE, + mLargeView.getVisibility()); + } + + @SmallTest + public void testOpenIntoAGap() { + inflate(R.layout.size_adaptive_gappy); + + SizeAdaptiveLayout.LayoutParams smallParams = + (SizeAdaptiveLayout.LayoutParams) mSmallView.getLayoutParams(); + SizeAdaptiveLayout.LayoutParams largeParams = + (SizeAdaptiveLayout.LayoutParams) mLargeView.getLayoutParams(); + assertTrue("gappy layout should have a gap", + smallParams.maxHeight + 10 < largeParams.minHeight); + int height = (int) smallParams.maxHeight + 10; + + measureAndLayout(height); + + assertTrue("one and only one view should be visible", + mLargeView.getVisibility() != mSmallView.getVisibility()); + // behavior is undefined in this case. + } + + @SmallTest + public void testOpenIntoAnOverlap() { + inflate(R.layout.size_adaptive_overlapping); + + SizeAdaptiveLayout.LayoutParams smallParams = + (SizeAdaptiveLayout.LayoutParams) mSmallView.getLayoutParams(); + SizeAdaptiveLayout.LayoutParams largeParams = + (SizeAdaptiveLayout.LayoutParams) mLargeView.getLayoutParams(); + assertEquals("overlapping layout should overlap", + smallParams.minHeight, + largeParams.minHeight); + int height = (int) smallParams.maxHeight; + + measureAndLayout(height); + + assertTrue("one and only one view should be visible", + mLargeView.getVisibility() != mSmallView.getVisibility()); + assertEquals("1U should get priority in an overlap because it is first", + View.VISIBLE, + mSmallView.getVisibility()); + } + + @SmallTest + public void testOpenThreeWayViewSmall() { + inflate(R.layout.size_adaptive_three_way); + assertNotNull("mMediumView should not be NULL in the three view layout", mMediumView); + + SizeAdaptiveLayout.LayoutParams lp = + (SizeAdaptiveLayout.LayoutParams) mSmallView.getLayoutParams(); + int height = (int) lp.minHeight; + + measureAndLayout(height); + + assertEquals("1U should be visible", + View.VISIBLE, + mSmallView.getVisibility()); + assertEquals("2U should be gone", + View.GONE, + mMediumView.getVisibility()); + assertEquals("4U should be gone", + View.GONE, + mLargeView.getVisibility()); + } + + @SmallTest + public void testOpenThreeWayViewMedium() { + inflate(R.layout.size_adaptive_three_way); + assertNotNull("mMediumView should not be NULL in the three view layout", mMediumView); + + SizeAdaptiveLayout.LayoutParams lp = + (SizeAdaptiveLayout.LayoutParams) mMediumView.getLayoutParams(); + int height = (int) lp.minHeight; + + measureAndLayout(height); + + assertEquals("1U should be gone", + View.GONE, + mSmallView.getVisibility()); + assertEquals("2U should be visible", + View.VISIBLE, + mMediumView.getVisibility()); + assertEquals("4U should be gone", + View.GONE, + mLargeView.getVisibility()); + } + + @SmallTest + public void testOpenThreeWayViewLarge() { + inflate(R.layout.size_adaptive_three_way); + assertNotNull("mMediumView should not be NULL in the three view layout", mMediumView); + + SizeAdaptiveLayout.LayoutParams lp = + (SizeAdaptiveLayout.LayoutParams) mLargeView.getLayoutParams(); + int height = (int) lp.minHeight; + + measureAndLayout(height); + + assertEquals("1U should be gone", + View.GONE, + mSmallView.getVisibility()); + assertEquals("2U should be gone", + View.GONE, + mMediumView.getVisibility()); + assertEquals("4U should be visible", + View.VISIBLE, + mLargeView.getVisibility()); + } + + @SmallTest + public void testResizeWithoutAnimation() { + inflate(R.layout.size_adaptive); + + SizeAdaptiveLayout.LayoutParams largeParams = + (SizeAdaptiveLayout.LayoutParams) mLargeView.getLayoutParams(); + int startHeight = (int) largeParams.minHeight + 10; + int endHeight = (int) largeParams.minHeight + 10; + + measureAndLayout(startHeight); + + assertEquals("4U should be visible", + View.VISIBLE, + mLargeView.getVisibility()); + assertFalse("There should be no animation on initial rendering.", + mSizeAdaptiveLayout.getTransitionAnimation().isRunning()); + + measureAndLayout(endHeight); + + assertEquals("4U should still be visible", + View.VISIBLE, + mLargeView.getVisibility()); + assertFalse("There should be no animation on scale within a view.", + mSizeAdaptiveLayout.getTransitionAnimation().isRunning()); + } + + @SmallTest + public void testResizeWithAnimation() { + inflate(R.layout.size_adaptive); + + SizeAdaptiveLayout.LayoutParams smallParams = + (SizeAdaptiveLayout.LayoutParams) mSmallView.getLayoutParams(); + SizeAdaptiveLayout.LayoutParams largeParams = + (SizeAdaptiveLayout.LayoutParams) mLargeView.getLayoutParams(); + int startHeight = (int) largeParams.minHeight + 10; + int endHeight = (int) smallParams.maxHeight; + + measureAndLayout(startHeight); + + assertEquals("4U should be visible", + View.VISIBLE, + mLargeView.getVisibility()); + assertFalse("There should be no animation on initial rendering.", + mSizeAdaptiveLayout.getTransitionAnimation().isRunning()); + + measureAndLayout(endHeight); + + assertEquals("1U should now be visible", + View.VISIBLE, + mSmallView.getVisibility()); + assertTrue("There should be an animation on scale between views.", + mSizeAdaptiveLayout.getTransitionAnimation().isRunning()); + } + + @SmallTest + public void testModestyPanelChangesColorWhite() { + inflate(R.layout.size_adaptive_color); + View panel = mSizeAdaptiveLayout.getModestyPanel(); + assertTrue("ModestyPanel should have a ColorDrawable background", + panel.getBackground() instanceof ColorDrawable); + ColorDrawable panelColor = (ColorDrawable) panel.getBackground(); + ColorDrawable salColor = (ColorDrawable) mSizeAdaptiveLayout.getBackground(); + assertEquals("ModestyPanel color should match the SizeAdaptiveLayout", + panelColor.getColor(), salColor.getColor()); + } + + @SmallTest + public void testModestyPanelHasDefault() { + inflate(R.layout.size_adaptive); + View panel = mSizeAdaptiveLayout.getModestyPanel(); + assertNull("SizeAdaptiveLayout should have no background for this test", + mSizeAdaptiveLayout.getBackground()); + assertTrue("ModestyPanel should have a ColorDrawable background", + panel.getBackground() instanceof ColorDrawable); + } + + private void measureAndLayout(int height) { + // manually measure it, and lay it out + int measureSpec = View.MeasureSpec.makeMeasureSpec(height, View.MeasureSpec.AT_MOST); + mSizeAdaptiveLayout.measure(500, measureSpec); + mSizeAdaptiveLayout.layout(0, 0, 500, height); + } +} |