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