1 /* 2 * Copyright (C) 2009 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 17 package com.android.email.mail; 18 19 import com.android.email.mail.internet.BinaryTempFileBody; 20 import com.android.email.mail.internet.MimeBodyPart; 21 import com.android.email.mail.internet.MimeHeader; 22 import com.android.email.mail.internet.MimeMessage; 23 import com.android.email.mail.internet.MimeMultipart; 24 import com.android.email.mail.internet.TextBody; 25 import com.android.email.mail.store.LocalStore; 26 import com.android.email.provider.AttachmentProvider; 27 import com.android.email.provider.EmailContent; 28 29 import android.net.Uri; 30 31 import java.io.IOException; 32 import java.util.ArrayList; 33 34 /** 35 * Utility class makes it easier for developer to build mail message objects. 36 * <p> 37 * Typical usage of these helper functions and builder objects are as follows. 38 * <p> 39 * <pre> 40 * String text2 = new TextBuilder("<html>").text("<head></head>") 41 * .text("<body>").cidImg("contetid@domain").text("</body>").build("</html"); 42 * String text2 = new TextBuilder("<html>").text("<head></head>") 43 * .text("<body>").uriImg(contentUri).text("</body>").build("</html"); 44 * Message msg = new MessageBuilder() 45 * .setBody(new MultipartBuilder("multipart/mixed") 46 * .addBodyPart(MessageTestUtils.imagePart("image/jpeg", null, 30, store)) 47 * .addBodyPart(MessageTestUtils.imagePart("application/pdf", cid1, aid1, store)) 48 * .addBodyPart(new MultipartBuilder("multipart/related") 49 * .addBodyPart(MessageTestUtils.textPart("text/html", text2 + text1)) 50 * .addBodyPart(MessageTestUtils.imagePart("image/jpg", cid1, aid1, store)) 51 * .addBodyPart(MessageTestUtils.imagePart("image/gif", cid2, aid2, store)) 52 * .buildBodyPart()) 53 * .addBodyPart(MessageTestUtils.imagePart("application/pdf", cid2, aid2, store)) 54 * .build()) 55 * .build(); 56 * </pre> 57 */ 58 59 public class MessageTestUtils { 60 61 /** 62 * Generate AttachmentProvider content URI from attachment ID and Account. 63 * 64 * @param attachmentId attachment id 65 * @param account Account object 66 * @return AttachmentProvider content URI 67 */ contentUri(long attachmentId, EmailContent.Account account)68 public static Uri contentUri(long attachmentId, EmailContent.Account account) { 69 return AttachmentProvider.getAttachmentUri(account.mId, attachmentId); 70 } 71 72 /** 73 * Create simple MimeBodyPart. 74 * 75 * @param mimeType MIME type of body part 76 * @param contentId content-id header value (optional - null for no header) 77 * @return MimeBodyPart object which body is null. 78 * @throws MessagingException 79 */ bodyPart(String mimeType, String contentId)80 public static BodyPart bodyPart(String mimeType, String contentId) throws MessagingException { 81 final MimeBodyPart bp = new MimeBodyPart(null, mimeType); 82 if (contentId != null) { 83 bp.setHeader(MimeHeader.HEADER_CONTENT_ID, contentId); 84 } 85 return bp; 86 } 87 88 /** 89 * Create MimeBodyPart with TextBody. 90 * 91 * @param mimeType MIME type of text 92 * @param text body text string 93 * @return MimeBodyPart object whose body is TextBody 94 * @throws MessagingException 95 */ textPart(String mimeType, String text)96 public static BodyPart textPart(String mimeType, String text) throws MessagingException { 97 final TextBody textBody = new TextBody(text); 98 final MimeBodyPart textPart = new MimeBodyPart(textBody); 99 textPart.setHeader(MimeHeader.HEADER_CONTENT_TYPE, mimeType); 100 return textPart; 101 } 102 103 /** 104 * Create attachment BodyPart with content-id. 105 * 106 * @param mimeType MIME type of image body 107 * @param contentId content-id header value (optional - null for no header) 108 * @param attachmentId attachment id of store 109 * @param store LocalStore which stores attachment 110 * @return LocalAttachmentBodyPart with content-id 111 * @throws MessagingException 112 * @throws IOException 113 */ imagePart(String mimeType, String contentId, long attachmentId, LocalStore store)114 public static BodyPart imagePart(String mimeType, String contentId, 115 long attachmentId, LocalStore store) throws MessagingException, IOException { 116 final BinaryTempFileBody imageBody = new BinaryTempFileBody(); 117 final LocalStore.LocalAttachmentBodyPart imagePart = 118 store.new LocalAttachmentBodyPart(imageBody, attachmentId); 119 imagePart.setHeader(MimeHeader.HEADER_CONTENT_TYPE, mimeType); 120 if (contentId != null) { 121 imagePart.setHeader(MimeHeader.HEADER_CONTENT_ID, contentId); 122 } 123 return imagePart; 124 } 125 126 /** 127 * Builder class for Multipart. 128 * 129 * This builder object accepts any number of BodyParts and then can produce 130 * Multipart or BodyPart which contains accepted BodyParts. Usually combined with other 131 * builder object and helper method. 132 */ 133 public static class MultipartBuilder { 134 private final String mContentType; 135 private final ArrayList<BodyPart> mParts = new ArrayList<BodyPart>(); 136 137 /** 138 * Create builder object with MIME type and dummy boundary string. 139 * 140 * @param mimeType MIME type of this Multipart 141 */ MultipartBuilder(String mimeType)142 public MultipartBuilder(String mimeType) { 143 this(mimeType, "this_is_boundary"); 144 } 145 146 /** 147 * Create builder object with MIME type and boundary string. 148 * 149 * @param mimeType MIME type of this Multipart 150 * @param boundary boundary string 151 */ MultipartBuilder(String mimeType, String boundary)152 public MultipartBuilder(String mimeType, String boundary) { 153 mContentType = mimeType + "; boundary=" + boundary; 154 } 155 156 /** 157 * Modifier method to add BodyPart to intended Multipart. 158 * 159 * @param bodyPart BodyPart to be added 160 * @return builder object itself 161 */ addBodyPart(final BodyPart bodyPart)162 public MultipartBuilder addBodyPart(final BodyPart bodyPart) { 163 mParts.add(bodyPart); 164 return this; 165 } 166 167 /** 168 * Build method to create Multipart. 169 * 170 * @return intended Multipart object 171 * @throws MessagingException 172 */ build()173 public Multipart build() throws MessagingException { 174 final MimeMultipart mp = new MimeMultipart(mContentType); 175 for (BodyPart p : mParts) { 176 mp.addBodyPart(p); 177 } 178 return mp; 179 } 180 181 /** 182 * Build method to create BodyPart that contains this "Multipart" 183 * @return BodyPart whose body is intended Multipart. 184 * @throws MessagingException 185 */ buildBodyPart()186 public BodyPart buildBodyPart() throws MessagingException { 187 final BodyPart bp = new MimeBodyPart(); 188 bp.setBody(this.build()); 189 return bp; 190 } 191 } 192 193 /** 194 * Builder class for Message 195 * 196 * This builder object accepts Body and then can produce Message object. 197 * Usually combined with other builder object and helper method. 198 */ 199 public static class MessageBuilder { 200 private Body mBody; 201 202 /** 203 * Create Builder object. 204 */ MessageBuilder()205 public MessageBuilder() { 206 } 207 208 /** 209 * Modifier method to set Body. 210 * 211 * @param body Body of intended Message 212 * @return builder object itself 213 */ setBody(final Body body)214 public MessageBuilder setBody(final Body body) { 215 mBody = body; 216 return this; 217 } 218 219 /** 220 * Build method to create Message. 221 * 222 * @return intended Message object 223 * @throws MessagingException 224 */ build()225 public Message build() throws MessagingException { 226 final MimeMessage msg = new MimeMessage(); 227 if (mBody == null) { 228 throw new MessagingException("body is not specified"); 229 } 230 msg.setBody(mBody); 231 return msg; 232 } 233 } 234 235 /** 236 * Builder class for simple HTML String. 237 * This builder object accepts some type of object or and string and then create String object. 238 * Usually combined with other builder object and helper method. 239 */ 240 public static class TextBuilder { 241 final StringBuilder mBuilder = new StringBuilder(); 242 243 /** 244 * Create builder with preamble string 245 * @param preamble 246 */ TextBuilder(String preamble)247 public TextBuilder(String preamble) { 248 mBuilder.append(preamble); 249 } 250 251 /** 252 * Modifier method to add img tag that has cid: src attribute. 253 * @param contentId content id string 254 * @return builder object itself 255 */ addCidImg(String contentId)256 public TextBuilder addCidImg(String contentId) { 257 return addTag("img", "SRC", "cid:" + contentId); 258 } 259 260 /** 261 * Modifier method to add img tag that has content:// src attribute. 262 * @param contentUri content uri object 263 * @return builder object itself 264 */ addUidImg(Uri contentUri)265 public TextBuilder addUidImg(Uri contentUri) { 266 return addTag("img", "src", contentUri.toString()); 267 } 268 269 /** 270 * Modifier method to add tag with specified attribute and value. 271 * 272 * @param tag tag name 273 * @param attribute attribute name 274 * @param value attribute value 275 * @return builder object itself 276 */ addTag(String tag, String attribute, String value)277 public TextBuilder addTag(String tag, String attribute, String value) { 278 return addText(String.format("<%s %s=\"%s\">", tag, attribute, value)); 279 } 280 281 /** 282 * Modifier method to add simple string. 283 * @param text string to add 284 * @return builder object itself 285 */ addText(String text)286 public TextBuilder addText(String text) { 287 mBuilder.append(text); 288 return this; 289 } 290 291 /** 292 * Build method to create intended String 293 * @param epilogue string to add to the end 294 * @return intended String 295 */ build(String epilogue)296 public String build(String epilogue) { 297 mBuilder.append(epilogue); 298 return mBuilder.toString(); 299 } 300 } 301 302 } 303