AttachmentTileGrid.java revision 4cb51dbce9635f4bf68a6de88f759e2f86d20325
1/* 2 * Copyright (C) 2011 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17package com.android.mail.ui; 18 19import android.content.Context; 20import android.net.Uri; 21import android.util.AttributeSet; 22import android.view.LayoutInflater; 23import android.view.View; 24import android.widget.FrameLayout; 25 26import com.android.mail.R; 27import com.android.mail.browse.MessageAttachmentTile; 28import com.android.mail.compose.ComposeAttachmentTile; 29import com.android.mail.providers.Attachment; 30 31import java.util.List; 32 33/** 34 * Acts as a grid composed of {@link AttachmentTile}s. 35 */ 36public class AttachmentTileGrid extends FrameLayout { 37 private LayoutInflater mInflater; 38 private Uri mAttachmentsListUri; 39 private final int mTileMinSize; 40 private int mColumnCount; 41 private List<Attachment> mAttachments; 42 43 public AttachmentTileGrid(Context context, AttributeSet attrs) { 44 super(context, attrs); 45 mInflater = LayoutInflater.from(context); 46 mTileMinSize = context.getResources() 47 .getDimensionPixelSize(R.dimen.attachment_tile_min_size); 48 } 49 50 /** 51 * Configures the grid to add {@link Attachment}s information to the views. 52 */ 53 public void configureGrid(Uri attachmentsListUri, List<Attachment> list) { 54 mAttachmentsListUri = attachmentsListUri; 55 mAttachments = list; 56 // Adding tiles to grid and filling in attachment information 57 int index = 0; 58 for (Attachment attachment : list) { 59 addMessageTileFromAttachment(attachment, index++); 60 } 61 } 62 63 private void addMessageTileFromAttachment(Attachment attachment, int index) { 64 final AttachmentTile attachmentTile; 65 66 if (getChildCount() <= index) { 67 attachmentTile = MessageAttachmentTile.inflate(mInflater, this); 68 addView(attachmentTile); 69 } else { 70 attachmentTile = (AttachmentTile) getChildAt(index); 71 } 72 73 attachmentTile.render(attachment, mAttachmentsListUri, index); 74 } 75 76 public ComposeAttachmentTile addComposeTileFromAttachment(Attachment attachment) { 77 final ComposeAttachmentTile attachmentTile = 78 ComposeAttachmentTile.inflate(mInflater, this); 79 80 addView(attachmentTile); 81 attachmentTile.render(attachment, null, -1); 82 83 return attachmentTile; 84 } 85 86 @Override 87 protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { 88 onMeasureForTiles(widthMeasureSpec); 89 } 90 91 private void onMeasureForTiles(int widthMeasureSpec) { 92 final int width = MeasureSpec.getSize(widthMeasureSpec); 93 94 final int childCount = getChildCount(); 95 if (childCount == 0) { 96 // Just in case... 97 setMeasuredDimension(width, 0); 98 return; 99 } 100 101 // Divide width by minimum tile size to get the number of columns. 102 // Truncation will ensure that the minimum will always be the minimum 103 // but that the tiles can (and likely will) grow larger. 104 mColumnCount = width / mTileMinSize; 105 106 // Just in case... 107 if (mColumnCount == 0) { 108 mColumnCount = 1; 109 } 110 111 // 1. Calculate image size. 112 // = [total width] / [child count] 113 // 114 // 2. Set it to width/height of each children. 115 // If we have a remainder, some tiles will have 116 // 1 pixel larger width than its height. 117 // 118 // 3. Set the dimensions of itself. 119 // Let width = given width. 120 // Let height = image size + bottom padding. 121 final int imageSize = (width) / mColumnCount; 122 final int remainder = width - (imageSize * mColumnCount); 123 124 for (int i = 0; i < childCount; i++) { 125 final View child = getChildAt(i); 126 // Compensate for the remainder 127 final int childWidth = imageSize + (i < remainder ? 1 : 0); 128 child.measure( 129 MeasureSpec.makeMeasureSpec(childWidth, MeasureSpec.EXACTLY), 130 MeasureSpec.makeMeasureSpec(imageSize, MeasureSpec.EXACTLY) 131 ); 132 } 133 134 // Calculate the number of rows so we can get the proper height. 135 // Then multiply by the height of one tile to get the grid height. 136 final int numRows = ((childCount - 1) / mColumnCount) + 1; 137 setMeasuredDimension(width, 138 numRows*(imageSize + getChildAt(0).getPaddingBottom())); 139 } 140 141 @Override 142 protected void onLayout(boolean changed, int left, int top, int right, int bottom) { 143 onLayoutForTiles(); 144 } 145 146 private void onLayoutForTiles() { 147 final int count = getChildCount(); 148 int childLeft = 0; 149 int childTop = 0; 150 boolean skipBeginningOfRowFirstTime = true; 151 152 // Layout the grid. 153 for (int i = 0; i < count; i++) { 154 final View child = getChildAt(i); 155 156 // Note MeasuredWidth and MeasuredHeight include the padding. 157 final int childWidth = child.getMeasuredWidth(); 158 final int childHeight = child.getMeasuredHeight(); 159 160 // If we're at the beginning of a row and it is not the first row 161 // in the grid, reset childLeft to 0 and update childTop 162 // to reflect the top of the new row. 163 if (!skipBeginningOfRowFirstTime && i % mColumnCount == 0) { 164 childLeft = 0; 165 childTop += childHeight; 166 } else { 167 skipBeginningOfRowFirstTime = false; 168 } 169 170 child.layout(childLeft, childTop, 171 childLeft + childWidth, childTop + childHeight); 172 childLeft += childWidth; 173 } 174 } 175 176 @Override 177 public void sendAccessibilityEvent(int eventType) { 178 // This method is called when the child tile is INVISIBLE (meaning "empty"), and the 179 // Accessibility Manager needs to find alternative content description to speak. 180 // Here, we ignore the default behavior, since we don't want to let the manager speak 181 // a contact name for the tile next to the INVISIBLE tile. 182 } 183 184 public List<Attachment> getAttachments() { 185 return mAttachments; 186 } 187} 188