Merge "SliceView better measuring / updated heights and alignment"
diff --git a/slices/view/src/androidTest/java/androidx/app/slice/render/SliceRenderer.java b/slices/view/src/androidTest/java/androidx/app/slice/render/SliceRenderer.java
index 056af32..dc9196e 100644
--- a/slices/view/src/androidTest/java/androidx/app/slice/render/SliceRenderer.java
+++ b/slices/view/src/androidTest/java/androidx/app/slice/render/SliceRenderer.java
@@ -65,7 +65,7 @@
protected void onLayout(boolean changed, int l, int t, int r, int b) {
int width = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 900,
mContext.getResources().getDisplayMetrics());
- int height = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 200,
+ int height = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 300,
mContext.getResources().getDisplayMetrics());
mLayout.measure(makeMeasureSpec(width, View.MeasureSpec.EXACTLY),
makeMeasureSpec(height, View.MeasureSpec.EXACTLY));
diff --git a/slices/view/src/main/java/androidx/app/slice/widget/GridContent.java b/slices/view/src/main/java/androidx/app/slice/widget/GridContent.java
index 41a9640..10a30ac 100644
--- a/slices/view/src/main/java/androidx/app/slice/widget/GridContent.java
+++ b/slices/view/src/main/java/androidx/app/slice/widget/GridContent.java
@@ -27,6 +27,9 @@
import static android.app.slice.SliceItem.FORMAT_TEXT;
import static android.app.slice.SliceItem.FORMAT_TIMESTAMP;
+import android.app.slice.Slice;
+import android.content.Context;
+import android.content.res.Resources;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.annotation.RestrictTo;
@@ -35,7 +38,9 @@
import java.util.List;
import androidx.app.slice.SliceItem;
+import androidx.app.slice.builders.GridBuilder;
import androidx.app.slice.core.SliceQuery;
+import androidx.app.slice.view.R;
/**
* Extracts information required to present content in a grid format from a slice.
@@ -50,9 +55,25 @@
private ArrayList<CellContent> mGridContent = new ArrayList<>();
private int mMaxCellLineCount;
private boolean mHasImage;
+ private @GridBuilder.ImageMode int mLargestImageMode;
- public GridContent(SliceItem gridItem) {
+ private int mBigPicMinHeight;
+ private int mBigPicMaxHeight;
+ private int mAllImagesHeight;
+ private int mImageTextHeight;
+ private int mMaxHeight;
+ private int mMinHeight;
+
+ public GridContent(Context context, SliceItem gridItem) {
populate(gridItem);
+
+ Resources res = context.getResources();
+ mBigPicMinHeight = res.getDimensionPixelSize(R.dimen.abc_slice_big_pic_min_height);
+ mBigPicMaxHeight = res.getDimensionPixelSize(R.dimen.abc_slice_big_pic_max_height);
+ mAllImagesHeight = res.getDimensionPixelSize(R.dimen.abc_slice_grid_image_only_height);
+ mImageTextHeight = res.getDimensionPixelSize(R.dimen.abc_slice_grid_image_text_height);
+ mMinHeight = res.getDimensionPixelSize(R.dimen.abc_slice_grid_min_height);
+ mMaxHeight = res.getDimensionPixelSize(R.dimen.abc_slice_grid_max_height);
}
private void reset() {
@@ -60,12 +81,13 @@
mMaxCellLineCount = 0;
mHasImage = false;
mGridContent.clear();
+ mLargestImageMode = 0;
}
/**
* @return whether this grid has content that is valid to display.
*/
- public boolean populate(SliceItem gridItem) {
+ private boolean populate(SliceItem gridItem) {
reset();
mColorItem = SliceQuery.findSubtype(gridItem, FORMAT_INT, SUBTYPE_COLOR);
String[] hints = new String[] {HINT_SHORTCUT, HINT_TITLE};
@@ -99,6 +121,7 @@
}
mMaxCellLineCount = Math.max(mMaxCellLineCount, cc.getTextCount());
mHasImage |= cc.hasImage();
+ mLargestImageMode = Math.max(mLargestImageMode, cc.getImageMode());
}
}
@@ -166,6 +189,37 @@
}
/**
+ * @return the height to display a grid row at when it is used as a small template.
+ */
+ public int getSmallHeight() {
+ return getHeight(true /* isSmall */);
+ }
+
+ /**
+ * @return the height the content in this template requires to be displayed.
+ */
+ public int getActualHeight() {
+ return getHeight(false /* isSmall */);
+ }
+
+ private int getHeight(boolean isSmall) {
+ if (!isValid()) {
+ return 0;
+ }
+ if (mAllImages) {
+ return mGridContent.size() == 1
+ ? isSmall ? mBigPicMinHeight : mBigPicMaxHeight
+ : mLargestImageMode == GridBuilder.ICON_IMAGE ? mMinHeight : mAllImagesHeight;
+ } else {
+ boolean twoLines = getMaxCellLineCount() > 1;
+ boolean hasImage = hasImage();
+ return (twoLines && !isSmall)
+ ? hasImage ? mMaxHeight : mMinHeight
+ : mLargestImageMode == GridBuilder.ICON_IMAGE ? mMinHeight : mImageTextHeight;
+ }
+ }
+
+ /**
* Extracts information required to present content in a cell.
* @hide
*/
@@ -175,6 +229,7 @@
private ArrayList<SliceItem> mCellItems = new ArrayList<>();
private int mTextCount;
private boolean mHasImage;
+ private int mImageMode = -1;
public CellContent(SliceItem cellItem) {
populate(cellItem);
@@ -207,6 +262,13 @@
mTextCount++;
mCellItems.add(item);
} else if (imageCount < 1 && FORMAT_IMAGE.equals(item.getFormat())) {
+ if (item.hasHint(Slice.HINT_NO_TINT)) {
+ mImageMode = item.hasHint(Slice.HINT_LARGE)
+ ? GridBuilder.LARGE_IMAGE
+ : GridBuilder.SMALL_IMAGE;
+ } else {
+ mImageMode = GridBuilder.ICON_IMAGE;
+ }
imageCount++;
mHasImage = true;
mCellItems.add(item);
@@ -269,5 +331,12 @@
public boolean hasImage() {
return mHasImage;
}
+
+ /**
+ * @return the mode of the image.
+ */
+ public int getImageMode() {
+ return mImageMode;
+ }
}
}
diff --git a/slices/view/src/main/java/androidx/app/slice/widget/GridRowView.java b/slices/view/src/main/java/androidx/app/slice/widget/GridRowView.java
index f267bdb..148730c 100644
--- a/slices/view/src/main/java/androidx/app/slice/widget/GridRowView.java
+++ b/slices/view/src/main/java/androidx/app/slice/widget/GridRowView.java
@@ -26,6 +26,8 @@
import static android.view.ViewGroup.LayoutParams.MATCH_PARENT;
import static android.view.ViewGroup.LayoutParams.WRAP_CONTENT;
+import static androidx.app.slice.widget.SliceView.MODE_SMALL;
+
import android.annotation.TargetApi;
import android.app.PendingIntent;
import android.content.Context;
@@ -67,15 +69,11 @@
private static final String TAG = "GridView";
- // TODO -- Should add notion to the builder so that apps could define the "see more" intent
- private static final boolean ALLOW_SEE_MORE = false;
-
private static final int TITLE_TEXT_LAYOUT = R.layout.abc_slice_title;
private static final int TEXT_LAYOUT = R.layout.abc_slice_secondary_text;
- // Max number of *just* images that can be shown in a row
- private static final int MAX_IMAGES = 3;
+
// Max number of normal cell items that can be shown in a row
- private static final int MAX_ALL = 5;
+ private static final int MAX_CELLS = 5;
// Max number of text items that can show in a cell
private static final int MAX_CELL_TEXT = 2;
@@ -85,12 +83,10 @@
private static final int MAX_CELL_IMAGES = 1;
private int mRowIndex;
- private boolean mIsAllImages;
-
+ private int mSmallImageSize;
private int mIconSize;
- private int mLargeIconSize;
- private int mBigPictureHeight;
- private int mAllImagesHeight;
+ private int mGutter;
+
private GridContent mGridContent;
private LinearLayout mViewContainer;
@@ -101,26 +97,31 @@
public GridRowView(Context context, AttributeSet attrs) {
super(context, attrs);
final Resources res = getContext().getResources();
- mIconSize = res.getDimensionPixelSize(R.dimen.abc_slice_icon_size);
- mLargeIconSize = res.getDimensionPixelSize(R.dimen.abc_slice_large_icon_size);
- mBigPictureHeight = res.getDimensionPixelSize(R.dimen.abc_slice_grid_big_picture_height);
- mAllImagesHeight = res.getDimensionPixelSize(R.dimen.abc_slice_grid_image_only_height);
mViewContainer = new LinearLayout(getContext());
mViewContainer.setOrientation(LinearLayout.HORIZONTAL);
addView(mViewContainer, new LayoutParams(MATCH_PARENT, MATCH_PARENT));
+ mViewContainer.setGravity(Gravity.CENTER_VERTICAL);
+ mIconSize = res.getDimensionPixelSize(R.dimen.abc_slice_icon_size);
+ mSmallImageSize = res.getDimensionPixelSize(R.dimen.abc_slice_small_image_size);
+ mGutter = res.getDimensionPixelSize(R.dimen.abc_slice_grid_gutter);
+ }
+
+ @Override
+ public int getSmallHeight() {
+ // GridRow is small if its the first element in a list without a header presented in small
+ return mGridContent != null ? mGridContent.getSmallHeight() : 0;
+ }
+
+ @Override
+ public int getActualHeight() {
+ return mGridContent != null ? mGridContent.getActualHeight() : 0;
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
- if (mIsAllImages) {
- int count = getChildCount();
- int height = (count == 1) ? mBigPictureHeight : mAllImagesHeight;
- heightMeasureSpec = MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY);
- getLayoutParams().height = height;
- for (int i = 0; i < count; i++) {
- getChildAt(i).getLayoutParams().height = height;
- }
- }
+ int height = getMode() == MODE_SMALL ? getSmallHeight() : getActualHeight();
+ heightMeasureSpec = MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY);
+ mViewContainer.getLayoutParams().height = height;
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
@@ -128,20 +129,21 @@
public void setTint(@ColorInt int tintColor) {
super.setTint(tintColor);
if (mGridContent != null) {
+ GridContent gc = mGridContent;
// TODO -- could be smarter about this
resetView();
- populateViews(mGridContent);
+ populateViews(gc);
}
}
/**
- * This is called when GridView is the parent template.
+ * This is called when GridView is presented in small format.
*/
@Override
public void setSlice(Slice slice) {
resetView();
mRowIndex = 0;
- mGridContent = new GridContent(slice.getItems().get(0));
+ mGridContent = new GridContent(getContext(), slice.getItems().get(0));
populateViews(mGridContent);
}
@@ -154,7 +156,7 @@
resetView();
setSliceActionListener(observer);
mRowIndex = index;
- mGridContent = new GridContent(slice);
+ mGridContent = new GridContent(getContext(), slice);
populateViews(mGridContent);
}
@@ -166,17 +168,13 @@
mViewContainer.setTag(tagItem);
makeClickable(mViewContainer);
}
- mIsAllImages = gc.isAllImages();
ArrayList<GridContent.CellContent> cells = gc.getGridContent();
- final int max = mIsAllImages ? MAX_IMAGES : MAX_ALL;
for (int i = 0; i < cells.size(); i++) {
- if (isFull()) {
+ if (mViewContainer.getChildCount() >= MAX_CELLS) {
+ // TODO -- use item if it exists
break;
}
- addCell(cells.get(i), i, Math.min(cells.size(), max));
- }
- if (ALLOW_SEE_MORE && mIsAllImages && cells.size() > getChildCount()) {
- addSeeMoreCount(cells.size() - getChildCount());
+ addCell(cells.get(i), i, Math.min(cells.size(), MAX_CELLS));
}
}
@@ -199,15 +197,11 @@
mViewContainer.addView(frame);
}
- private boolean isFull() {
- return getChildCount() >= (mIsAllImages ? MAX_IMAGES : MAX_ALL);
- }
-
/**
* Adds a cell to the grid view based on the provided {@link SliceItem}.
*/
private void addCell(GridContent.CellContent cell, int index, int total) {
- final int maxCellText = getMode() == SliceView.MODE_SMALL
+ final int maxCellText = getMode() == MODE_SMALL
? MAX_CELL_TEXT_SMALL
: MAX_CELL_TEXT;
LinearLayout cellContainer = new LinearLayout(getContext());
@@ -223,7 +217,7 @@
boolean singleItem = cellItems.size() == 1;
List<SliceItem> textItems = null;
// In small format we display one text item and prefer titles
- if (!singleItem && getMode() == SliceView.MODE_SMALL) {
+ if (!singleItem && getMode() == MODE_SMALL) {
// Get all our text items
textItems = cellItems.stream().filter(new Predicate<SliceItem>() {
@Override
@@ -262,6 +256,12 @@
if (added) {
mViewContainer.addView(cellContainer,
new LinearLayout.LayoutParams(0, WRAP_CONTENT, 1));
+ if (index != total - 1) {
+ // If we're not the last or only element add space between items
+ MarginLayoutParams lp =
+ (LinearLayout.MarginLayoutParams) cellContainer.getLayoutParams();
+ lp.setMarginEnd(mGutter);
+ }
if (contentIntentItem != null) {
EventInfo info = new EventInfo(getMode(), EventInfo.ACTION_TYPE_BUTTON,
EventInfo.ROW_TYPE_GRID, mRowIndex);
@@ -295,15 +295,20 @@
} else if (FORMAT_IMAGE.equals(format)) {
ImageView iv = new ImageView(getContext());
iv.setImageIcon(item.getIcon());
- if (color != -1 && !item.hasHint(HINT_NO_TINT) && !item.hasHint(HINT_LARGE)) {
- iv.setColorFilter(color);
- }
- int size = mIconSize;
+ LinearLayout.LayoutParams lp;
if (item.hasHint(HINT_LARGE)) {
iv.setScaleType(ScaleType.CENTER_CROP);
- size = singleItem ? MATCH_PARENT : mLargeIconSize;
+ lp = new LinearLayout.LayoutParams(MATCH_PARENT, MATCH_PARENT);
+ } else {
+ boolean isIcon = !item.hasHint(HINT_NO_TINT);
+ int size = isIcon ? mIconSize : mSmallImageSize;
+ iv.setScaleType(isIcon ? ScaleType.CENTER_INSIDE : ScaleType.CENTER_CROP);
+ lp = new LinearLayout.LayoutParams(size, size);
}
- container.addView(iv, new LayoutParams(size, size));
+ if (color != -1 && !item.hasHint(HINT_NO_TINT)) {
+ iv.setColorFilter(color);
+ }
+ container.addView(iv, lp);
addedView = iv;
}
return addedView != null;
@@ -334,7 +339,6 @@
@Override
public void resetView() {
- mIsAllImages = true;
mViewContainer.removeAllViews();
}
}
diff --git a/slices/view/src/main/java/androidx/app/slice/widget/LargeTemplateView.java b/slices/view/src/main/java/androidx/app/slice/widget/LargeTemplateView.java
index 7aace75..bdd1ac5 100644
--- a/slices/view/src/main/java/androidx/app/slice/widget/LargeTemplateView.java
+++ b/slices/view/src/main/java/androidx/app/slice/widget/LargeTemplateView.java
@@ -16,9 +16,6 @@
package androidx.app.slice.widget;
-import static android.app.slice.Slice.HINT_PARTIAL;
-import static android.view.ViewGroup.LayoutParams.WRAP_CONTENT;
-
import android.annotation.TargetApi;
import android.content.Context;
import android.support.annotation.RestrictTo;
@@ -30,8 +27,6 @@
import androidx.app.slice.Slice;
import androidx.app.slice.SliceItem;
-import androidx.app.slice.core.SliceQuery;
-import androidx.app.slice.view.R;
/**
* @hide
@@ -42,7 +37,6 @@
private final LargeSliceAdapter mAdapter;
private final RecyclerView mRecyclerView;
- private final int mDefaultHeight;
private Slice mSlice;
private boolean mIsScrollable;
private ListContent mListContent;
@@ -54,7 +48,11 @@
mAdapter = new LargeSliceAdapter(context);
mRecyclerView.setAdapter(mAdapter);
addView(mRecyclerView);
- mDefaultHeight = getResources().getDimensionPixelSize(R.dimen.abc_slice_large_height);
+ }
+
+ @Override
+ public int getActualHeight() {
+ return mListContent != null ? mListContent.getListHeight() : 0;
}
@Override
@@ -82,20 +80,6 @@
}
@Override
- protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
- mRecyclerView.getLayoutParams().height = WRAP_CONTENT;
- super.onMeasure(widthMeasureSpec, heightMeasureSpec);
- int width = MeasureSpec.getSize(widthMeasureSpec);
- if (mRecyclerView.getMeasuredHeight() > width
- || (mSlice != null && SliceQuery.hasHints(mSlice, HINT_PARTIAL))) {
- mRecyclerView.getLayoutParams().height = width;
- } else {
- mRecyclerView.getLayoutParams().height = mRecyclerView.getMeasuredHeight();
- }
- super.onMeasure(widthMeasureSpec, heightMeasureSpec);
- }
-
- @Override
public void setSlice(Slice slice) {
mSlice = slice;
populate();
@@ -111,7 +95,7 @@
if (mSlice == null) {
return;
}
- mListContent = new ListContent(mSlice);
+ mListContent = new ListContent(getContext(), mSlice);
mAdapter.setSliceItems(mListContent.getRowItems(), mTintColor);
}
@@ -128,6 +112,5 @@
mSlice = null;
mAdapter.setSliceItems(null, -1);
mListContent = null;
- mAdapter.setSliceItems(null, -1);
}
}
diff --git a/slices/view/src/main/java/androidx/app/slice/widget/ListContent.java b/slices/view/src/main/java/androidx/app/slice/widget/ListContent.java
index 79bfa39..246ef0b 100644
--- a/slices/view/src/main/java/androidx/app/slice/widget/ListContent.java
+++ b/slices/view/src/main/java/androidx/app/slice/widget/ListContent.java
@@ -17,6 +17,7 @@
package androidx.app.slice.widget;
import static android.app.slice.Slice.HINT_ACTIONS;
+import static android.app.slice.Slice.HINT_HORIZONTAL;
import static android.app.slice.Slice.HINT_LIST_ITEM;
import static android.app.slice.Slice.HINT_SHORTCUT;
import static android.app.slice.Slice.SUBTYPE_COLOR;
@@ -25,6 +26,7 @@
import static android.app.slice.SliceItem.FORMAT_SLICE;
import static android.app.slice.SliceItem.FORMAT_TEXT;
+import android.content.Context;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.annotation.RestrictTo;
@@ -48,8 +50,10 @@
private SliceItem mColorItem;
private ArrayList<SliceItem> mRowItems = new ArrayList<>();
private List<SliceItem> mSliceActions;
+ private Context mContext;
- public ListContent(Slice slice) {
+ public ListContent(Context context, Slice slice) {
+ mContext = context;
populate(slice);
}
@@ -65,7 +69,7 @@
/**
* @return whether this row has content that is valid to display.
*/
- public boolean populate(Slice slice) {
+ private boolean populate(Slice slice) {
reset();
mColorItem = SliceQuery.findSubtype(slice, FORMAT_INT, SUBTYPE_COLOR);
// Find slice actions
@@ -98,6 +102,24 @@
}
/**
+ * @return the total height of all the rows contained in this list.
+ */
+ public int getListHeight() {
+ int height = 0;
+ for (int i = 0; i < mRowItems.size(); i++) {
+ SliceItem item = mRowItems.get(i);
+ if (item.hasHint(HINT_HORIZONTAL)) {
+ GridContent gc = new GridContent(mContext, item);
+ height += gc.getActualHeight();
+ } else {
+ RowContent rc = new RowContent(mContext, item, i == 0 /* isHeader */);
+ height += rc.getActualHeight();
+ }
+ }
+ return height;
+ }
+
+ /**
* @return whether this list has content that is valid to display.
*/
public boolean isValid() {
diff --git a/slices/view/src/main/java/androidx/app/slice/widget/RowContent.java b/slices/view/src/main/java/androidx/app/slice/widget/RowContent.java
index 920dc52..a22a37d 100644
--- a/slices/view/src/main/java/androidx/app/slice/widget/RowContent.java
+++ b/slices/view/src/main/java/androidx/app/slice/widget/RowContent.java
@@ -30,8 +30,10 @@
import static androidx.app.slice.core.SliceHints.SUBTYPE_RANGE;
+import android.content.Context;
import android.support.annotation.Nullable;
import android.support.annotation.RestrictTo;
+import android.text.TextUtils;
import android.util.Log;
import java.util.ArrayList;
@@ -39,6 +41,7 @@
import androidx.app.slice.SliceItem;
import androidx.app.slice.core.SliceQuery;
+import androidx.app.slice.view.R;
/**
* Extracts information required to present content in a row format from a slice.
@@ -57,9 +60,14 @@
private boolean mEndItemsContainAction;
private SliceItem mRange;
private boolean mIsHeader;
+ private int mLineCount = 0;
+ private int mMaxHeight;
+ private int mMinHeight;
- public RowContent(SliceItem rowSlice, boolean isHeader) {
+ public RowContent(Context context, SliceItem rowSlice, boolean isHeader) {
populate(rowSlice, isHeader);
+ mMaxHeight = context.getResources().getDimensionPixelSize(R.dimen.abc_slice_row_max_height);
+ mMinHeight = context.getResources().getDimensionPixelSize(R.dimen.abc_slice_row_min_height);
}
/**
@@ -72,12 +80,13 @@
mSubtitleItem = null;
mEndItems.clear();
mIsHeader = false;
+ mLineCount = 0;
}
/**
* @return whether this row has content that is valid to display.
*/
- public boolean populate(SliceItem rowSlice, boolean isHeader) {
+ private boolean populate(SliceItem rowSlice, boolean isHeader) {
reset();
mIsHeader = isHeader;
if (!isValidRow(rowSlice)) {
@@ -131,6 +140,12 @@
endItems.add(item);
}
}
+ if (hasText(mTitleItem)) {
+ mLineCount++;
+ }
+ if (hasText(mSubtitleItem)) {
+ mLineCount++;
+ }
// Special rules for end items: only one timestamp, can't be mixture of icons / actions
boolean hasTimestamp = mStartItem != null
&& FORMAT_TIMESTAMP.equals(mStartItem.getFormat());
@@ -212,6 +227,33 @@
}
/**
+ * @return the number of lines of text contained in this row.
+ */
+ public int getLineCount() {
+ return mLineCount;
+ }
+
+ /**
+ * @return the height to display a row at when it is used as a small template.
+ */
+ public int getSmallHeight() {
+ return mMaxHeight;
+ }
+
+ /**
+ * @return the height the content in this template requires to be displayed.
+ */
+ public int getActualHeight() {
+ return isValid()
+ ? (getLineCount() > 1 || mIsHeader) ? mMaxHeight : mMinHeight
+ : 0;
+ }
+
+ private static boolean hasText(SliceItem textSlice) {
+ return textSlice != null && !TextUtils.isEmpty(textSlice.getText());
+ }
+
+ /**
* @return whether this is a valid item to use to populate a row of content.
*/
private static boolean isValidRow(SliceItem rowSlice) {
diff --git a/slices/view/src/main/java/androidx/app/slice/widget/RowView.java b/slices/view/src/main/java/androidx/app/slice/widget/RowView.java
index 5b3e74c..bcd4f61 100644
--- a/slices/view/src/main/java/androidx/app/slice/widget/RowView.java
+++ b/slices/view/src/main/java/androidx/app/slice/widget/RowView.java
@@ -109,6 +109,19 @@
mSeekBar = (SeekBar) findViewById(R.id.seek_bar);
mProgressBar = (ProgressBar) findViewById(R.id.progress_bar);
}
+
+
+ @Override
+ public int getSmallHeight() {
+ // RowView is in small format when it is the header of a list and displays at max height.
+ return mRowContent != null && mRowContent.isValid() ? mRowContent.getSmallHeight() : 0;
+ }
+
+ @Override
+ public int getActualHeight() {
+ return mRowContent != null && mRowContent.isValid() ? mRowContent.getActualHeight() : 0;
+ }
+
@Override
public void setTint(@ColorInt int tintColor) {
super.setTint(tintColor);
@@ -126,6 +139,13 @@
}
}
+ @Override
+ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+ int height = getMode() == MODE_SMALL ? getSmallHeight() : getActualHeight();
+ heightMeasureSpec = MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY);
+ super.onMeasure(widthMeasureSpec, heightMeasureSpec);
+ }
+
/**
* This is called when RowView is being used as a component in a large template.
*/
@@ -136,7 +156,7 @@
mRowIndex = index;
mIsHeader = isHeader;
mHeaderActions = null;
- mRowContent = new RowContent(slice, mIsHeader);
+ mRowContent = new RowContent(getContext(), slice, mIsHeader);
populateViews();
}
@@ -148,8 +168,8 @@
mRowIndex = 0;
mIsHeader = true;
mHeaderActions = null;
- ListContent lc = new ListContent(slice);
- mRowContent = new RowContent(lc.getHeaderItem(), true /* isHeader */);
+ ListContent lc = new ListContent(getContext(), slice);
+ mRowContent = new RowContent(getContext(), lc.getHeaderItem(), true /* isHeader */);
populateViews();
}
diff --git a/slices/view/src/main/java/androidx/app/slice/widget/SliceChildView.java b/slices/view/src/main/java/androidx/app/slice/widget/SliceChildView.java
index 9a5279f..9768894 100644
--- a/slices/view/src/main/java/androidx/app/slice/widget/SliceChildView.java
+++ b/slices/view/src/main/java/androidx/app/slice/widget/SliceChildView.java
@@ -75,6 +75,20 @@
}
/**
+ * @return the height of this view when displayed in {@link SliceView#MODE_SMALL}.
+ */
+ public int getSmallHeight() {
+ return 0;
+ }
+
+ /**
+ * @return the height of this view if it displayed all of its contents.
+ */
+ public int getActualHeight() {
+ return 0;
+ }
+
+ /**
* @param slice the slice to show in this view.
*/
public abstract void setSlice(Slice slice);
diff --git a/slices/view/src/main/java/androidx/app/slice/widget/SliceView.java b/slices/view/src/main/java/androidx/app/slice/widget/SliceView.java
index 3648234..6e1f0c0 100644
--- a/slices/view/src/main/java/androidx/app/slice/widget/SliceView.java
+++ b/slices/view/src/main/java/androidx/app/slice/widget/SliceView.java
@@ -114,13 +114,7 @@
*/
public static final int MODE_SHORTCUT = 3;
- /**
- * Will select the type of slice binding based on size of the View. TODO: Put in some info about
- * that selection.
- */
- private static final int MODE_AUTO = 0;
-
- private int mMode = MODE_AUTO;
+ private int mMode = MODE_LARGE;
private Slice mCurrentSlice;
private SliceChildView mCurrentView;
private List<SliceItem> mActions;
@@ -130,6 +124,8 @@
private boolean mIsScrollable = true;
private final int mShortcutSize;
+ private final int mMinLargeHeight;
+
private AttributeSet mAttrs;
private int mThemeTintColor = -1;
@@ -161,44 +157,73 @@
mActionRow = new ActionRow(getContext(), true);
mActionRow.setBackground(new ColorDrawable(0xffeeeeee));
mCurrentView = new LargeTemplateView(getContext());
+ mCurrentView.setMode(getMode());
addView(mCurrentView.getView(), getChildLp(mCurrentView.getView()));
addView(mActionRow, getChildLp(mActionRow));
mShortcutSize = getContext().getResources()
.getDimensionPixelSize(R.dimen.abc_slice_shortcut_size);
+ mMinLargeHeight = getResources().getDimensionPixelSize(R.dimen.abc_slice_large_height);
+ }
+
+ private int getHeightForMode() {
+ int mode = getMode();
+ if (mode == MODE_SHORTCUT) {
+ return mShortcutSize;
+ }
+ return mode == MODE_LARGE
+ ? mCurrentView.getActualHeight()
+ : mCurrentView.getSmallHeight();
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int width = MeasureSpec.getSize(widthMeasureSpec);
int childWidth = MeasureSpec.getSize(widthMeasureSpec);
- int childHeight = MeasureSpec.getSize(heightMeasureSpec);
if (MODE_SHORTCUT == mMode) {
- // TODO: consider scaling the shortcut to fit
+ // TODO: consider scaling the shortcut to fit if too small
childWidth = mShortcutSize;
width = mShortcutSize;
}
+
+ final int actionHeight = mActionRow.getVisibility() != View.GONE
+ ? mActionRow.getMeasuredHeight()
+ : 0;
+ final int sliceHeight = getHeightForMode() + actionHeight;
+ final int heightAvailable = MeasureSpec.getSize(heightMeasureSpec);
+ final int heightMode = MeasureSpec.getMode(heightMeasureSpec);
+ int height = heightAvailable;
+ if (heightAvailable >= sliceHeight) {
+ // Available space is larger than the slice
+ if (heightMode == MeasureSpec.AT_MOST || heightMode == MeasureSpec.UNSPECIFIED) {
+ height = sliceHeight;
+ }
+ } else {
+ // Not enough space available for slice in current mode
+ if (getMode() == MODE_LARGE && heightAvailable >= mMinLargeHeight + actionHeight) {
+ // It's just a slice with scrolling content; cap it to height available.
+ height = heightAvailable;
+ } else if (getMode() == MODE_SHORTCUT) {
+ // TODO: consider scaling the shortcut to fit if too small
+ height = mShortcutSize;
+ }
+ }
+ heightMeasureSpec = MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY);
+
+ // Measure the children without the padding
final int left = getPaddingLeft();
final int top = getPaddingTop();
final int right = getPaddingRight();
final int bot = getPaddingBottom();
-
- // Measure the children without the padding
+ int childHeight = MeasureSpec.getSize(heightMeasureSpec);
childWidth -= left + right;
childHeight -= top + bot;
int childWidthMeasureSpec = MeasureSpec.makeMeasureSpec(childWidth, MeasureSpec.EXACTLY);
int childHeightMeasureSpec = MeasureSpec.makeMeasureSpec(childHeight, MeasureSpec.EXACTLY);
measureChildren(childWidthMeasureSpec, childHeightMeasureSpec);
- // Figure out parent height
- int actionHeight = mActionRow.getVisibility() != View.GONE
- ? mActionRow.getMeasuredHeight()
- : 0;
- int currViewHeight = mCurrentView.getView().getMeasuredHeight() + top + bot;
- int newHeightSpec = MeasureSpec.makeMeasureSpec(currViewHeight + actionHeight,
- MeasureSpec.EXACTLY);
// Figure out parent width
width += left + right;
- setMeasuredDimension(width, newHeightSpec);
+ setMeasuredDimension(width, heightMeasureSpec);
}
@Override
@@ -334,9 +359,6 @@
* @return the mode this view is presenting in.
*/
public @SliceMode int getMode() {
- if (mMode == MODE_AUTO) {
- return MODE_LARGE;
- }
return mMode;
}
@@ -375,7 +397,7 @@
mCurrentView.resetView();
return;
}
- ListContent lc = new ListContent(mCurrentSlice);
+ ListContent lc = new ListContent(getContext(), mCurrentSlice);
if (!lc.isValid()) {
mCurrentView.resetView();
mCurrentView.setVisibility(View.GONE);
@@ -397,7 +419,7 @@
}
addView(mCurrentView.getView(), getChildLp(mCurrentView.getView()));
addView(mActionRow, getChildLp(mActionRow));
- mCurrentView.setMode(mMode);
+ mCurrentView.setMode(mode);
}
// Scrolling
if (mode == MODE_LARGE && (mCurrentView instanceof LargeTemplateView)) {
@@ -451,7 +473,8 @@
if (child instanceof ShortcutView) {
return new LayoutParams(mShortcutSize, mShortcutSize);
} else {
- return new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT);
+ return new LayoutParams(LayoutParams.MATCH_PARENT,
+ LayoutParams.MATCH_PARENT);
}
}
@@ -462,8 +485,6 @@
@RestrictTo(RestrictTo.Scope.LIBRARY)
public static String modeToString(@SliceMode int mode) {
switch(mode) {
- case MODE_AUTO:
- return "MODE AUTO";
case MODE_SHORTCUT:
return "MODE SHORTCUT";
case MODE_SMALL:
diff --git a/slices/view/src/main/res/layout-v21/abc_slice_small_template.xml b/slices/view/src/main/res/layout-v21/abc_slice_small_template.xml
deleted file mode 100644
index 7707dae..0000000
--- a/slices/view/src/main/res/layout-v21/abc_slice_small_template.xml
+++ /dev/null
@@ -1,89 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- ~ Copyright 2017 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.
- -->
-<LinearLayout
- xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:minHeight="@dimen/abc_slice_row_min_height"
- android:maxHeight="@dimen/abc_slice_row_max_height"
- android:gravity="center_vertical"
- android:background="?android:attr/activatedBackgroundIndicator"
- android:clipToPadding="false">
-
- <LinearLayout
- android:id="@+id/icon_frame"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:gravity="start|center_vertical"
- android:orientation="horizontal"
- android:paddingEnd="12dp"
- android:paddingTop="4dp"
- android:paddingBottom="4dp"/>
-
- <LinearLayout
- android:id="@android:id/content"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_weight="1"
- android:gravity="center_vertical"
- android:orientation="vertical">
-
- <TextView android:id="@android:id/title"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:maxLines="2"
- android:textAppearance="?android:attr/textAppearanceListItem" />
-
- <TextView android:id="@android:id/summary"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_alignStart="@android:id/title"
- android:textAppearance="?android:attr/textAppearanceListItemSecondary"
- android:textColor="?android:attr/textColorSecondary"
- android:maxLines="10" />
-
- <SeekBar
- android:id="@+id/seek_bar"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:visibility="gone" />
-
- <ProgressBar
- android:id="@+id/progress_bar"
- style="?android:attr/progressBarStyleHorizontal"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:visibility="gone" />
-
- </LinearLayout>
-
- <View
- android:id="@+id/divider"
- android:layout_width="1dp"
- android:layout_height="match_parent"
- android:layout_marginTop="8dp"
- android:layout_marginBottom="8dp"
- android:background="?android:attr/listDivider"
- android:visibility="gone"/>
-
- <LinearLayout android:id="@android:id/widget_frame"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:gravity="end|center_vertical"
- android:orientation="horizontal" />
-
-</LinearLayout>
diff --git a/slices/view/src/main/res/layout/abc_slice_grid.xml b/slices/view/src/main/res/layout/abc_slice_grid.xml
index 890f77d..e4cf7c5 100644
--- a/slices/view/src/main/res/layout/abc_slice_grid.xml
+++ b/slices/view/src/main/res/layout/abc_slice_grid.xml
@@ -17,8 +17,7 @@
<androidx.app.slice.widget.GridRowView
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:minHeight="@dimen/abc_slice_grid_image_only_height"
+ android:layout_height="match_parent"
android:gravity="center_vertical"
android:background="?android:attr/activatedBackgroundIndicator"
android:clipToPadding="false">
diff --git a/slices/view/src/main/res/layout/abc_slice_secondary_text.xml b/slices/view/src/main/res/layout/abc_slice_secondary_text.xml
index b446ddd..0870465 100644
--- a/slices/view/src/main/res/layout/abc_slice_secondary_text.xml
+++ b/slices/view/src/main/res/layout/abc_slice_secondary_text.xml
@@ -23,4 +23,6 @@
android:gravity="center"
android:layout_height="wrap_content"
android:padding="4dp"
- android:layout_width="match_parent" />
+ android:layout_width="match_parent"
+ android:maxLines="1"
+ android:ellipsize="end"/>
diff --git a/slices/view/src/main/res/layout/abc_slice_small_template.xml b/slices/view/src/main/res/layout/abc_slice_small_template.xml
index 2d5e913..4a47c06 100644
--- a/slices/view/src/main/res/layout/abc_slice_small_template.xml
+++ b/slices/view/src/main/res/layout/abc_slice_small_template.xml
@@ -17,11 +17,11 @@
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:minHeight="@dimen/abc_slice_row_min_height"
- android:maxHeight="@dimen/abc_slice_row_max_height"
+ android:layout_height="match_parent"
android:gravity="center_vertical"
+ android:layout_gravity="center_vertical"
android:background="?android:attr/activatedBackgroundIndicator"
+ android:orientation="horizontal"
android:clipToPadding="false">
<LinearLayout
@@ -34,8 +34,8 @@
<LinearLayout
android:id="@android:id/content"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
+ android:layout_width="0dp"
+ android:layout_height="match_parent"
android:layout_weight="1"
android:gravity="center_vertical"
android:orientation="vertical">
@@ -43,13 +43,13 @@
<TextView android:id="@android:id/title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:maxLines="2"/>
+ android:maxLines="1"/>
<TextView android:id="@android:id/summary"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignStart="@android:id/title"
- android:maxLines="10" />
+ android:maxLines="1" />
<SeekBar
android:id="@+id/seek_bar"
diff --git a/slices/view/src/main/res/layout/abc_slice_title.xml b/slices/view/src/main/res/layout/abc_slice_title.xml
index e1bdf03..70a1400 100644
--- a/slices/view/src/main/res/layout/abc_slice_title.xml
+++ b/slices/view/src/main/res/layout/abc_slice_title.xml
@@ -23,4 +23,6 @@
android:gravity="center"
android:layout_height="wrap_content"
android:padding="4dp"
- android:layout_width="match_parent" />
+ android:layout_width="match_parent"
+ android:maxLines="1"
+ android:ellipsize="end"/>
diff --git a/slices/view/src/main/res/values/dimens.xml b/slices/view/src/main/res/values/dimens.xml
index ff2fb97..04d74f3 100644
--- a/slices/view/src/main/res/values/dimens.xml
+++ b/slices/view/src/main/res/values/dimens.xml
@@ -17,17 +17,18 @@
<resources>
<!-- General -->
- <!-- Size of normal icons / images in a slice -->
+ <!-- Size of icons in a slice -->
<dimen name="abc_slice_icon_size">24dp</dimen>
- <!-- Size of large icons / images in a slice -->
- <dimen name="abc_slice_large_icon_size">48dp</dimen>
+ <!-- Size of small images in a slice -->
+ <dimen name="abc_slice_small_image_size">48dp</dimen>
<!-- Standard padding used in a slice -->
<dimen name="abc_slice_padding">16dp</dimen>
<!-- Size of a slice shortcut view -->
<dimen name="abc_slice_shortcut_size">56dp</dimen>
-
- <!-- Height of a large template -->
+ <!-- Minimum height of a small template -->
+ <dimen name="abc_slice_small_height">48dp</dimen>
+ <!-- Minimum height of a large template -->
<dimen name="abc_slice_large_height">240dp</dimen>
<!-- Row view sizes-->
@@ -39,10 +40,22 @@
<dimen name="abc_slice_row_active_input_height">120dp</dimen>
<!-- Grid view sizes-->
- <!-- Height of a grid row displaying only images -->
+ <!-- Height of a grid row displaying only text or only small images (but not both) -->
+ <dimen name="abc_slice_grid_min_height">60dp</dimen>
+ <!-- Height of a grid row displaying only large images -->
<dimen name="abc_slice_grid_image_only_height">86dp</dimen>
- <!-- Height of a grid row showing text and images -->
- <dimen name="abc_slice_grid_height">120dp</dimen>
- <!-- Height of expanded grid row if showing a single large image -->
- <dimen name="abc_slice_grid_big_picture_height">180dp</dimen>
+ <!-- Height of a grid row showing one text item along with a large image -->
+ <dimen name="abc_slice_grid_image_text_height">120dp</dimen>
+ <!-- Height of a grid row showing two text items along with a large image -->
+ <dimen name="abc_slice_grid_max_height">140dp</dimen>
+ <!-- Height of a grid row showing 1-2 text items along with a small image -->
+ <dimen name="abc_slice_grid_small_image_text_height">120dp</dimen>
+ <!-- Gutter between cells in a grid row-->
+ <dimen name="abc_slice_grid_gutter">4dp</dimen>
+
+ <!-- Big picture -->
+ <!-- Min height of row showing a single large image -->
+ <dimen name="abc_slice_big_pic_min_height">120dp</dimen>
+ <!-- Max height of row showing a single large image -->
+ <dimen name="abc_slice_big_pic_max_height">140dp</dimen>
</resources>
\ No newline at end of file