1 /* 2 * Copyright (C) 2012 Google Inc. 3 * Licensed to The Android Open Source Project. 4 * 5 * Licensed under the Apache License, Version 2.0 (the "License"); 6 * you may not use this file except in compliance with the License. 7 * You may obtain a copy of the License at 8 * 9 * http://www.apache.org/licenses/LICENSE-2.0 10 * 11 * Unless required by applicable law or agreed to in writing, software 12 * distributed under the License is distributed on an "AS IS" BASIS, 13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 * See the License for the specific language governing permissions and 15 * limitations under the License. 16 */ 17 18 package com.android.mail.browse; 19 20 import android.app.FragmentManager; 21 import android.app.LoaderManager; 22 import android.content.Context; 23 import android.content.Loader; 24 import android.database.Cursor; 25 import android.net.Uri; 26 import android.os.Bundle; 27 import android.util.AttributeSet; 28 import android.view.LayoutInflater; 29 import android.view.View; 30 import android.widget.LinearLayout; 31 import android.widget.TextView; 32 33 import com.android.mail.R; 34 import com.android.mail.browse.AttachmentLoader.AttachmentCursor; 35 import com.android.mail.browse.ConversationContainer.DetachListener; 36 import com.android.mail.browse.ConversationViewAdapter.MessageHeaderItem; 37 import com.android.mail.providers.Attachment; 38 import com.android.mail.providers.Message; 39 import com.android.mail.ui.AttachmentTile; 40 import com.android.mail.ui.AttachmentTileGrid; 41 import com.android.mail.utils.LogTag; 42 import com.android.mail.utils.LogUtils; 43 44 import com.google.common.base.Objects; 45 import com.google.common.collect.Lists; 46 47 import java.util.ArrayList; 48 import java.util.List; 49 50 public class MessageFooterView extends LinearLayout implements DetachListener, 51 LoaderManager.LoaderCallbacks<Cursor> { 52 53 private MessageHeaderItem mMessageHeaderItem; 54 private LoaderManager mLoaderManager; 55 private FragmentManager mFragmentManager; 56 private AttachmentCursor mAttachmentsCursor; 57 private TextView mTitleText; 58 private AttachmentTileGrid mAttachmentGrid; 59 private LinearLayout mAttachmentBarList; 60 61 private final LayoutInflater mInflater; 62 63 private static final String LOG_TAG = LogTag.getLogTag(); 64 65 private Uri mAccountUri; 66 67 public MessageFooterView(Context context) { 68 this(context, null); 69 } 70 71 public MessageFooterView(Context context, AttributeSet attrs) { 72 super(context, attrs); 73 74 mInflater = LayoutInflater.from(context); 75 } 76 77 @Override 78 protected void onFinishInflate() { 79 super.onFinishInflate(); 80 81 mTitleText = (TextView) findViewById(R.id.attachments_header_text); 82 mAttachmentGrid = (AttachmentTileGrid) findViewById(R.id.attachment_tile_grid); 83 mAttachmentBarList = (LinearLayout) findViewById(R.id.attachment_bar_list); 84 } 85 86 public void initialize(LoaderManager loaderManager, FragmentManager fragmentManager) { 87 mLoaderManager = loaderManager; 88 mFragmentManager = fragmentManager; 89 } 90 91 public void bind(MessageHeaderItem headerItem, Uri accountUri, boolean measureOnly) { 92 mAccountUri = accountUri; 93 94 // Resets the footer view. This step is only done if the 95 // attachmentsListUri changes so that we don't 96 // repeat the work of layout and measure when 97 // we're only updating the attachments. 98 if (mMessageHeaderItem != null && 99 mMessageHeaderItem.getMessage() != null && 100 mMessageHeaderItem.getMessage().attachmentListUri != null && 101 !mMessageHeaderItem.getMessage().attachmentListUri.equals( 102 headerItem.getMessage().attachmentListUri)) { 103 mAttachmentGrid.removeAllViewsInLayout(); 104 mAttachmentBarList.removeAllViewsInLayout(); 105 mTitleText.setVisibility(View.GONE); 106 mAttachmentGrid.setVisibility(View.GONE); 107 mAttachmentBarList.setVisibility(View.GONE); 108 } 109 110 // If this MessageFooterView is being bound to a new attachment, we need to unbind with the 111 // old loader 112 final Integer oldAttachmentLoaderId = getAttachmentLoaderId(); 113 114 mMessageHeaderItem = headerItem; 115 116 final Integer attachmentLoaderId = getAttachmentLoaderId(); 117 // Destroy the loader if we are attempting to load a different attachment 118 if (oldAttachmentLoaderId != null && 119 !Objects.equal(oldAttachmentLoaderId, attachmentLoaderId)) { 120 mLoaderManager.destroyLoader(oldAttachmentLoaderId); 121 } 122 123 // kick off load of Attachment objects in background thread 124 // but don't do any Loader work if we're only measuring 125 if (!measureOnly && attachmentLoaderId != null) { 126 LogUtils.i(LOG_TAG, "binding footer view, calling initLoader for message %d", 127 attachmentLoaderId); 128 mLoaderManager.initLoader(attachmentLoaderId, Bundle.EMPTY, this); 129 } 130 131 // Do an initial render if initLoader didn't already do one 132 if (mAttachmentGrid.getChildCount() == 0 && 133 mAttachmentBarList.getChildCount() == 0) { 134 renderAttachments(false); 135 } 136 setVisibility(mMessageHeaderItem.isExpanded() ? VISIBLE : GONE); 137 } 138 139 private void renderAttachments(boolean loaderResult) { 140 final List<Attachment> attachments; 141 if (mAttachmentsCursor != null && !mAttachmentsCursor.isClosed()) { 142 int i = -1; 143 attachments = Lists.newArrayList(); 144 while (mAttachmentsCursor.moveToPosition(++i)) { 145 attachments.add(mAttachmentsCursor.get()); 146 } 147 } else { 148 // before the attachment loader results are in, we can still render immediately using 149 // the basic info in the message's attachmentsJSON 150 attachments = mMessageHeaderItem.getMessage().getAttachments(); 151 } 152 renderAttachments(attachments, loaderResult); 153 } 154 155 private void renderAttachments(List<Attachment> attachments, boolean loaderResult) { 156 if (attachments == null || attachments.isEmpty()) { 157 return; 158 } 159 160 // filter the attachments into tiled and non-tiled 161 final int maxSize = attachments.size(); 162 final List<Attachment> tiledAttachments = new ArrayList<Attachment>(maxSize); 163 final List<Attachment> barAttachments = new ArrayList<Attachment>(maxSize); 164 165 for (Attachment attachment : attachments) { 166 if (AttachmentTile.isTiledAttachment(attachment)) { 167 tiledAttachments.add(attachment); 168 } else { 169 barAttachments.add(attachment); 170 } 171 } 172 mMessageHeaderItem.getMessage().attachmentsJson = Attachment.toJSONArray(attachments); 173 174 mTitleText.setVisibility(View.VISIBLE); 175 176 renderTiledAttachments(tiledAttachments, loaderResult); 177 renderBarAttachments(barAttachments, loaderResult); 178 } 179 180 private void renderTiledAttachments(List<Attachment> tiledAttachments, boolean loaderResult) { 181 mAttachmentGrid.setVisibility(View.VISIBLE); 182 183 // Setup the tiles. 184 mAttachmentGrid.configureGrid(mFragmentManager, 185 mMessageHeaderItem.getMessage().attachmentListUri, tiledAttachments, loaderResult); 186 } 187 188 private void renderBarAttachments(List<Attachment> barAttachments, boolean loaderResult) { 189 mAttachmentBarList.setVisibility(View.VISIBLE); 190 191 for (Attachment attachment : barAttachments) { 192 final Uri id = attachment.getIdentifierUri(); 193 MessageAttachmentBar barAttachmentView = 194 (MessageAttachmentBar) mAttachmentBarList.findViewWithTag(id); 195 196 if (barAttachmentView == null) { 197 barAttachmentView = MessageAttachmentBar.inflate(mInflater, this); 198 barAttachmentView.setTag(id); 199 barAttachmentView.initialize(mFragmentManager); 200 mAttachmentBarList.addView(barAttachmentView); 201 } 202 203 barAttachmentView.render(attachment, mAccountUri, loaderResult); 204 } 205 } 206 207 private Integer getAttachmentLoaderId() { 208 Integer id = null; 209 final Message msg = mMessageHeaderItem == null ? null : mMessageHeaderItem.getMessage(); 210 if (msg != null && msg.hasAttachments && msg.attachmentListUri != null) { 211 id = msg.attachmentListUri.hashCode(); 212 } 213 return id; 214 } 215 216 @Override 217 public void onDetachedFromParent() { 218 // Do nothing 219 } 220 221 @Override 222 public Loader<Cursor> onCreateLoader(int id, Bundle args) { 223 return new AttachmentLoader(getContext(), 224 mMessageHeaderItem.getMessage().attachmentListUri); 225 } 226 227 @Override 228 public void onLoadFinished(Loader<Cursor> loader, Cursor data) { 229 mAttachmentsCursor = (AttachmentCursor) data; 230 231 if (mAttachmentsCursor == null || mAttachmentsCursor.isClosed()) { 232 return; 233 } 234 235 renderAttachments(true); 236 } 237 238 @Override 239 public void onLoaderReset(Loader<Cursor> loader) { 240 mAttachmentsCursor = null; 241 } 242 } 243