AttachmentTileGrid.java revision a6e8789043b567a54cb930dd785fba573cf65f5c
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.app.FragmentManager; 20import android.content.Context; 21import android.graphics.Bitmap; 22import android.net.Uri; 23import android.util.AttributeSet; 24import android.view.LayoutInflater; 25import android.view.View; 26import android.widget.FrameLayout; 27 28import com.android.mail.R; 29import com.android.mail.browse.MessageAttachmentTile; 30import com.android.mail.compose.ComposeAttachmentTile; 31import com.android.mail.providers.Attachment; 32import com.android.mail.ui.AttachmentTile.AttachmentPreview; 33import com.android.mail.ui.AttachmentTile.AttachmentPreviewCache; 34import com.android.mail.utils.AttachmentUtils; 35import com.google.common.collect.Lists; 36import com.google.common.collect.Maps; 37 38import java.util.ArrayList; 39import java.util.HashMap; 40import java.util.List; 41 42/** 43 * Acts as a grid composed of {@link AttachmentTile}s. 44 */ 45public class AttachmentTileGrid extends FrameLayout implements AttachmentPreviewCache { 46 private LayoutInflater mInflater; 47 private Uri mAttachmentsListUri; 48 private final int mTileMinSize; 49 private final int mTileMaxSize; 50 private int mColumnCount; 51 private List<Attachment> mAttachments; 52 private HashMap<String, AttachmentPreview> mAttachmentPreviews; 53 private FragmentManager mFragmentManager; 54 55 public AttachmentTileGrid(Context context, AttributeSet attrs) { 56 super(context, attrs); 57 mInflater = LayoutInflater.from(context); 58 mTileMinSize = context.getResources() 59 .getDimensionPixelSize(R.dimen.attachment_tile_min_size); 60 mTileMaxSize = context.getResources() 61 .getDimensionPixelSize(R.dimen.attachment_tile_max_size); 62 mAttachmentPreviews = Maps.newHashMap(); 63 } 64 65 /** 66 * Configures the grid to add {@link Attachment}s information to the views. 67 */ 68 public void configureGrid(FragmentManager fragmentManager, Uri attachmentsListUri, 69 List<Attachment> list, boolean loaderResult) { 70 mFragmentManager = fragmentManager; 71 mAttachmentsListUri = attachmentsListUri; 72 mAttachments = list; 73 // Adding tiles to grid and filling in attachment information 74 int index = 0; 75 for (Attachment attachment : list) { 76 addMessageTileFromAttachment(attachment, index++, loaderResult); 77 } 78 } 79 80 private void addMessageTileFromAttachment(Attachment attachment, int index, 81 boolean loaderResult) { 82 final MessageAttachmentTile attachmentTile; 83 84 if (getChildCount() <= index) { 85 attachmentTile = MessageAttachmentTile.inflate(mInflater, this); 86 attachmentTile.initialize(mFragmentManager); 87 addView(attachmentTile); 88 } else { 89 attachmentTile = (MessageAttachmentTile) getChildAt(index); 90 } 91 92 attachmentTile.render(attachment, mAttachmentsListUri, index, this, loaderResult); 93 } 94 95 public ComposeAttachmentTile addComposeTileFromAttachment(Attachment attachment) { 96 final ComposeAttachmentTile attachmentTile = 97 ComposeAttachmentTile.inflate(mInflater, this); 98 99 addView(attachmentTile); 100 attachmentTile.render(attachment, null, -1, this, false); 101 102 return attachmentTile; 103 } 104 105 @Override 106 protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { 107 onMeasureForTiles(widthMeasureSpec); 108 } 109 110 private void onMeasureForTiles(int widthMeasureSpec) { 111 final int width = MeasureSpec.getSize(widthMeasureSpec); 112 113 final int childCount = getChildCount(); 114 if (childCount == 0) { 115 // Just in case... 116 setMeasuredDimension(width, 0); 117 return; 118 } 119 120 // Divide width by minimum tile size to get the number of columns. 121 // Truncation will ensure that the minimum will always be the minimum 122 // but that the tiles can (and likely will) grow larger. 123 mColumnCount = width / mTileMinSize; 124 125 // Just in case... 126 if (mColumnCount == 0) { 127 mColumnCount = 1; 128 } 129 130 // 1. Calculate image size. 131 // = [total width] / [child count] 132 // 133 // 2. Set it to width/height of each children. 134 // If we have a remainder, some tiles will have 135 // 1 pixel larger width than its height. 136 // 137 // 3. Set the dimensions of itself. 138 // Let width = given width. 139 // Let height = image size + bottom padding. 140 141 // b/7204811: Hack for measure. set imageSize to max size. We'd rather have too much 142 // whitespace, than overlapping overlays 143 final int imageSize = mTileMaxSize; //(width) / mColumnCount; 144 final int remainder = width - (imageSize * mColumnCount); 145 146 for (int i = 0; i < childCount; i++) { 147 final View child = getChildAt(i); 148 // Compensate for the remainder 149 final int childWidth = imageSize + (i < remainder ? 1 : 0); 150 child.measure( 151 MeasureSpec.makeMeasureSpec(childWidth, MeasureSpec.EXACTLY), 152 MeasureSpec.makeMeasureSpec(imageSize, MeasureSpec.EXACTLY) 153 ); 154 } 155 156 // Calculate the number of rows so we can get the proper height. 157 // Then multiply by the height of one tile to get the grid height. 158 final int numRows = ((childCount - 1) / mColumnCount) + 1; 159 setMeasuredDimension(width, 160 numRows*(imageSize + getChildAt(0).getPaddingBottom())); 161 } 162 163 @Override 164 protected void onLayout(boolean changed, int left, int top, int right, int bottom) { 165 onLayoutForTiles(); 166 } 167 168 private void onLayoutForTiles() { 169 final int count = getChildCount(); 170 int childLeft = 0; 171 int childTop = 0; 172 boolean skipBeginningOfRowFirstTime = true; 173 174 // Layout the grid. 175 for (int i = 0; i < count; i++) { 176 final View child = getChildAt(i); 177 178 // Note MeasuredWidth and MeasuredHeight include the padding. 179 final int childWidth = child.getMeasuredWidth(); 180 final int childHeight = child.getMeasuredHeight(); 181 182 // If we're at the beginning of a row and it is not the first row 183 // in the grid, reset childLeft to 0 and update childTop 184 // to reflect the top of the new row. 185 if (!skipBeginningOfRowFirstTime && i % mColumnCount == 0) { 186 childLeft = 0; 187 childTop += childHeight; 188 } else { 189 skipBeginningOfRowFirstTime = false; 190 } 191 192 child.layout(childLeft, childTop, 193 childLeft + childWidth, childTop + childHeight); 194 childLeft += childWidth; 195 } 196 } 197 198 @Override 199 public void sendAccessibilityEvent(int eventType) { 200 // This method is called when the child tile is INVISIBLE (meaning "empty"), and the 201 // Accessibility Manager needs to find alternative content description to speak. 202 // Here, we ignore the default behavior, since we don't want to let the manager speak 203 // a contact name for the tile next to the INVISIBLE tile. 204 } 205 206 public List<Attachment> getAttachments() { 207 return mAttachments; 208 } 209 210 public ArrayList<AttachmentPreview> getAttachmentPreviews() { 211 return Lists.newArrayList(mAttachmentPreviews.values()); 212 } 213 214 public void setAttachmentPreviews(ArrayList<AttachmentPreview> previews) { 215 if (previews != null) { 216 for (AttachmentPreview preview : previews) { 217 mAttachmentPreviews.put(preview.attachmentIdentifier, preview); 218 } 219 } 220 } 221 222 /* 223 * Save the preview for an attachment 224 */ 225 @Override 226 public void set(Attachment attachment, Bitmap preview) { 227 final String attachmentIdentifier = AttachmentUtils.getIdentifier(attachment); 228 if (attachmentIdentifier != null) { 229 mAttachmentPreviews.put( 230 attachmentIdentifier, new AttachmentPreview(attachment, preview)); 231 } 232 } 233 234 /* 235 * Returns a saved preview that was previously set 236 */ 237 @Override 238 public Bitmap get(Attachment attachment) { 239 final String attachmentIdentifier = AttachmentUtils.getIdentifier(attachment); 240 if (attachmentIdentifier != null) { 241 final AttachmentPreview attachmentPreview = mAttachmentPreviews.get( 242 attachmentIdentifier); 243 if (attachmentPreview != null) { 244 return attachmentPreview.preview; 245 } 246 } 247 return null; 248 } 249} 250