1 /* 2 * Copyright (C) 2015 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 package com.android.messaging.ui; 17 18 import android.content.Context; 19 import android.content.res.Resources; 20 import android.graphics.Rect; 21 import android.net.Uri; 22 import android.support.annotation.Nullable; 23 import android.text.TextUtils; 24 import android.view.LayoutInflater; 25 import android.view.View; 26 import android.view.View.OnClickListener; 27 import android.view.View.OnLongClickListener; 28 import android.view.ViewGroup; 29 import android.widget.FrameLayout.LayoutParams; 30 import android.widget.ImageView; 31 import android.widget.TextView; 32 33 import com.android.messaging.R; 34 import com.android.messaging.datamodel.DataModel; 35 import com.android.messaging.datamodel.data.MessagePartData; 36 import com.android.messaging.datamodel.data.PendingAttachmentData; 37 import com.android.messaging.datamodel.data.PersonItemData; 38 import com.android.messaging.datamodel.data.VCardContactItemData; 39 import com.android.messaging.datamodel.media.FileImageRequestDescriptor; 40 import com.android.messaging.datamodel.media.ImageRequest; 41 import com.android.messaging.datamodel.media.ImageRequestDescriptor; 42 import com.android.messaging.datamodel.media.UriImageRequestDescriptor; 43 import com.android.messaging.ui.MultiAttachmentLayout.OnAttachmentClickListener; 44 import com.android.messaging.ui.PersonItemView.PersonItemViewListener; 45 import com.android.messaging.util.Assert; 46 import com.android.messaging.util.ContentType; 47 import com.android.messaging.util.ImageUtils; 48 import com.android.messaging.util.UiUtils; 49 import com.android.messaging.util.UriUtil; 50 51 /** 52 * A view factory that creates previews for single/multiple attachments. 53 */ 54 public class AttachmentPreviewFactory { 55 /** Standalone attachment preview */ 56 public static final int TYPE_SINGLE = 1; 57 58 /** Attachment preview displayed in a multi-attachment layout */ 59 public static final int TYPE_MULTIPLE = 2; 60 61 /** Attachment preview displayed in the attachment chooser grid view */ 62 public static final int TYPE_CHOOSER_GRID = 3; 63 64 public static View createAttachmentPreview(final LayoutInflater layoutInflater, 65 final MessagePartData attachmentData, final ViewGroup parent, 66 final int viewType, final boolean startImageRequest, 67 @Nullable final OnAttachmentClickListener clickListener) { 68 final String contentType = attachmentData.getContentType(); 69 View attachmentView = null; 70 if (attachmentData instanceof PendingAttachmentData) { 71 attachmentView = createPendingAttachmentPreview(layoutInflater, parent, 72 (PendingAttachmentData) attachmentData); 73 } else if (ContentType.isImageType(contentType)) { 74 attachmentView = createImagePreview(layoutInflater, attachmentData, parent, viewType, 75 startImageRequest); 76 } else if (ContentType.isAudioType(contentType)) { 77 attachmentView = createAudioPreview(layoutInflater, attachmentData, parent, viewType); 78 } else if (ContentType.isVideoType(contentType)) { 79 attachmentView = createVideoPreview(layoutInflater, attachmentData, parent, viewType); 80 } else if (ContentType.isVCardType(contentType)) { 81 attachmentView = createVCardPreview(layoutInflater, attachmentData, parent, viewType); 82 } else { 83 Assert.fail("unsupported attachment type: " + contentType); 84 return null; 85 } 86 87 // Some views have a caption, set the text/visibility if one exists 88 final TextView captionView = (TextView) attachmentView.findViewById(R.id.caption); 89 if (captionView != null) { 90 final String caption = attachmentData.getText(); 91 captionView.setVisibility(TextUtils.isEmpty(caption) ? View.GONE : View.VISIBLE); 92 captionView.setText(caption); 93 } 94 95 if (attachmentView != null && clickListener != null) { 96 attachmentView.setOnClickListener(new OnClickListener() { 97 @Override 98 public void onClick(final View view) { 99 final Rect bounds = UiUtils.getMeasuredBoundsOnScreen(view); 100 clickListener.onAttachmentClick(attachmentData, bounds, 101 false /* longPress */); 102 } 103 }); 104 attachmentView.setOnLongClickListener(new OnLongClickListener() { 105 @Override 106 public boolean onLongClick(final View view) { 107 final Rect bounds = UiUtils.getMeasuredBoundsOnScreen(view); 108 return clickListener.onAttachmentClick(attachmentData, bounds, 109 true /* longPress */); 110 } 111 }); 112 } 113 return attachmentView; 114 } 115 116 public static MultiAttachmentLayout createMultiplePreview(final Context context, 117 final OnAttachmentClickListener listener) { 118 final MultiAttachmentLayout multiAttachmentLayout = 119 new MultiAttachmentLayout(context, null); 120 final ViewGroup.LayoutParams layoutParams = new ViewGroup.LayoutParams( 121 LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT); 122 multiAttachmentLayout.setLayoutParams(layoutParams); 123 multiAttachmentLayout.setOnAttachmentClickListener(listener); 124 return multiAttachmentLayout; 125 } 126 127 public static ImageRequestDescriptor getImageRequestDescriptorForAttachment( 128 final MessagePartData attachmentData, final int desiredWidth, final int desiredHeight) { 129 final Uri uri = attachmentData.getContentUri(); 130 final String contentType = attachmentData.getContentType(); 131 if (ContentType.isImageType(contentType)) { 132 final String filePath = UriUtil.getFilePathFromUri(uri); 133 if (filePath != null) { 134 return new FileImageRequestDescriptor(filePath, desiredWidth, desiredHeight, 135 attachmentData.getWidth(), attachmentData.getHeight(), 136 false /* canUseThumbnail */, true /* allowCompression */, 137 false /* isStatic */); 138 } else { 139 return new UriImageRequestDescriptor(uri, desiredWidth, desiredHeight, 140 attachmentData.getWidth(), attachmentData.getHeight(), 141 true /* allowCompression */, false /* isStatic */, false /*cropToCircle*/, 142 ImageUtils.DEFAULT_CIRCLE_BACKGROUND_COLOR /* circleBackgroundColor */, 143 ImageUtils.DEFAULT_CIRCLE_STROKE_COLOR /* circleStrokeColor */); 144 } 145 } 146 return null; 147 } 148 149 private static View createImagePreview(final LayoutInflater layoutInflater, 150 final MessagePartData attachmentData, final ViewGroup parent, 151 final int viewType, final boolean startImageRequest) { 152 int layoutId = R.layout.attachment_single_image; 153 switch (viewType) { 154 case AttachmentPreviewFactory.TYPE_SINGLE: 155 layoutId = R.layout.attachment_single_image; 156 break; 157 case AttachmentPreviewFactory.TYPE_MULTIPLE: 158 layoutId = R.layout.attachment_multiple_image; 159 break; 160 case AttachmentPreviewFactory.TYPE_CHOOSER_GRID: 161 layoutId = R.layout.attachment_chooser_image; 162 break; 163 default: 164 Assert.fail("unsupported attachment view type!"); 165 break; 166 } 167 final View view = layoutInflater.inflate(layoutId, parent, false /* attachToRoot */); 168 final AsyncImageView imageView = (AsyncImageView) view.findViewById( 169 R.id.attachment_image_view); 170 int maxWidth = imageView.getMaxWidth(); 171 int maxHeight = imageView.getMaxHeight(); 172 if (viewType == TYPE_CHOOSER_GRID) { 173 final Resources resources = layoutInflater.getContext().getResources(); 174 maxWidth = maxHeight = resources.getDimensionPixelSize( 175 R.dimen.attachment_grid_image_cell_size); 176 } 177 if (maxWidth <= 0 || maxWidth == Integer.MAX_VALUE) { 178 maxWidth = ImageRequest.UNSPECIFIED_SIZE; 179 } 180 if (maxHeight <= 0 || maxHeight == Integer.MAX_VALUE) { 181 maxHeight = ImageRequest.UNSPECIFIED_SIZE; 182 } 183 if (startImageRequest) { 184 imageView.setImageResourceId(getImageRequestDescriptorForAttachment(attachmentData, 185 maxWidth, maxHeight)); 186 } 187 imageView.setContentDescription( 188 parent.getResources().getString(R.string.message_image_content_description)); 189 return view; 190 } 191 192 private static View createPendingAttachmentPreview(final LayoutInflater layoutInflater, 193 final ViewGroup parent, final PendingAttachmentData attachmentData) { 194 final View pendingItemView = layoutInflater.inflate(R.layout.attachment_pending_item, 195 parent, false); 196 final ImageView imageView = (ImageView) 197 pendingItemView.findViewById(R.id.pending_item_view); 198 final ViewGroup.LayoutParams layoutParams = imageView.getLayoutParams(); 199 final int defaultSize = layoutInflater.getContext().getResources().getDimensionPixelSize( 200 R.dimen.pending_attachment_size); 201 layoutParams.width = attachmentData.getWidth() == MessagePartData.UNSPECIFIED_SIZE ? 202 defaultSize : attachmentData.getWidth(); 203 layoutParams.height = attachmentData.getHeight() == MessagePartData.UNSPECIFIED_SIZE ? 204 defaultSize : attachmentData.getHeight(); 205 return pendingItemView; 206 } 207 208 private static View createVCardPreview(final LayoutInflater layoutInflater, 209 final MessagePartData attachmentData, final ViewGroup parent, 210 final int viewType) { 211 int layoutId = R.layout.attachment_single_vcard; 212 switch (viewType) { 213 case AttachmentPreviewFactory.TYPE_SINGLE: 214 layoutId = R.layout.attachment_single_vcard; 215 break; 216 case AttachmentPreviewFactory.TYPE_MULTIPLE: 217 layoutId = R.layout.attachment_multiple_vcard; 218 break; 219 case AttachmentPreviewFactory.TYPE_CHOOSER_GRID: 220 layoutId = R.layout.attachment_chooser_vcard; 221 break; 222 default: 223 Assert.fail("unsupported attachment view type!"); 224 break; 225 } 226 final View view = layoutInflater.inflate(layoutId, parent, false /* attachToRoot */); 227 final PersonItemView vcardPreview = (PersonItemView) view.findViewById( 228 R.id.vcard_attachment_view); 229 vcardPreview.setAvatarOnly(viewType != AttachmentPreviewFactory.TYPE_SINGLE); 230 vcardPreview.bind(DataModel.get().createVCardContactItemData(layoutInflater.getContext(), 231 attachmentData)); 232 vcardPreview.setListener(new PersonItemViewListener() { 233 @Override 234 public void onPersonClicked(final PersonItemData data) { 235 Assert.isTrue(data instanceof VCardContactItemData); 236 final VCardContactItemData vCardData = (VCardContactItemData) data; 237 if (vCardData.hasValidVCard()) { 238 final Uri vCardUri = vCardData.getVCardUri(); 239 UIIntents.get().launchVCardDetailActivity(vcardPreview.getContext(), vCardUri); 240 } 241 } 242 243 @Override 244 public boolean onPersonLongClicked(final PersonItemData data) { 245 return false; 246 } 247 }); 248 return view; 249 } 250 251 private static View createAudioPreview(final LayoutInflater layoutInflater, 252 final MessagePartData attachmentData, final ViewGroup parent, 253 final int viewType) { 254 int layoutId = R.layout.attachment_single_audio; 255 switch (viewType) { 256 case AttachmentPreviewFactory.TYPE_SINGLE: 257 layoutId = R.layout.attachment_single_audio; 258 break; 259 case AttachmentPreviewFactory.TYPE_MULTIPLE: 260 layoutId = R.layout.attachment_multiple_audio; 261 break; 262 case AttachmentPreviewFactory.TYPE_CHOOSER_GRID: 263 layoutId = R.layout.attachment_chooser_audio; 264 break; 265 default: 266 Assert.fail("unsupported attachment view type!"); 267 break; 268 } 269 final View view = layoutInflater.inflate(layoutId, parent, false /* attachToRoot */); 270 final AudioAttachmentView audioView = (AudioAttachmentView) 271 view.findViewById(R.id.audio_attachment_view); 272 audioView.bindMessagePartData( 273 attachmentData, false /* incoming */, false /* showAsSelected */); 274 return view; 275 } 276 277 private static View createVideoPreview(final LayoutInflater layoutInflater, 278 final MessagePartData attachmentData, final ViewGroup parent, 279 final int viewType) { 280 int layoutId = R.layout.attachment_single_video; 281 switch (viewType) { 282 case AttachmentPreviewFactory.TYPE_SINGLE: 283 layoutId = R.layout.attachment_single_video; 284 break; 285 case AttachmentPreviewFactory.TYPE_MULTIPLE: 286 layoutId = R.layout.attachment_multiple_video; 287 break; 288 case AttachmentPreviewFactory.TYPE_CHOOSER_GRID: 289 layoutId = R.layout.attachment_chooser_video; 290 break; 291 default: 292 Assert.fail("unsupported attachment view type!"); 293 break; 294 } 295 final VideoThumbnailView videoThumbnail = (VideoThumbnailView) layoutInflater.inflate( 296 layoutId, parent, false /* attachToRoot */); 297 videoThumbnail.setSource(attachmentData, false /* incomingMessage */); 298 return videoThumbnail; 299 } 300 } 301