Java tutorial
/* * ================================================================================================= * Copyright (C) 2014 Martin Albedinsky * ================================================================================================= * Licensed under the Apache License, Version 2.0 or later (further "License" only). * ------------------------------------------------------------------------------------------------- * You may use this file only in compliance with the License. More details and copy of this License * you may obtain at * * http://www.apache.org/licenses/LICENSE-2.0 * * You can redistribute, modify or publish any part of the code written within this file but as it * is described in the License, the software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES or CONDITIONS OF ANY KIND. * * See the License for the specific language governing permissions and limitations under the License. * ================================================================================================= */ package com.albedinsky.android.support.intent; import android.app.Activity; import android.content.Intent; import android.net.Uri; import android.support.annotation.NonNull; import android.support.annotation.Nullable; import android.support.annotation.StringRes; import android.support.v4.app.Fragment; import android.util.Log; import android.util.Patterns; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.List; import java.util.regex.Matcher; /** * A {@link BaseIntent} builder implementation providing API for building of intents targeting * a <b>e-mail</b> related applications. * <p> * Primary e-mail addresses can be specified via {@link #to(String)} or {@link #to(String...)}. * <b>Carbon copy</b> addresses can be specified via {@link #cc(String)} or {@link #cc(String...)}. * If you want to include also <b>blind carbon copy</b> addresses, these can be specified via * {@link #bcc(String)} or {@link #bcc(String...)}. * * @author Martin Albedinsky */ public class EmailIntent extends BaseIntent<EmailIntent> { /** * Interface =================================================================================== */ /** * Constants =================================================================================== */ /** * Log TAG. */ private static final String TAG = "EmailIntent"; /** * Uri scheme for <b>e-mail</b> targeting intents. * <p> * Constant value: <b>mailto</b> */ public static final String URI_SCHEME = "mailto"; /** * Static members ============================================================================== */ /** * Matcher for valid e-mail address. */ protected static final Matcher EMAIL_MATCHER = Patterns.EMAIL_ADDRESS.matcher(""); /** * Members ===================================================================================== */ /** * Subject of an email to send. */ private CharSequence mSubject; /** * Message of an email to send. */ private CharSequence mMessage; /** * Array with e-mail addresses to send e-mail to. */ private List<String> mAddresses; /** * Array with e-mail addresses for carbon copy to send e-mail to. */ private List<String> mCcAddresses; /** * Array with e-mail addresses for blind carbon copy to send e-mail to. */ private List<String> mBccAddresses; /** * Constructors ================================================================================ */ /** * Creates a new instance of EmailIntent for the given <var>activity</var> context. * See {@link com.albedinsky.android.support.intent.BaseIntent#BaseIntent(Activity)} * for additional info. */ public EmailIntent(@NonNull Activity activity) { super(activity); } /** * Creates a new instance of EmailIntent for the given <var>fragment</var> context. * See {@link com.albedinsky.android.support.intent.BaseIntent#BaseIntent(android.support.v4.app.Fragment)} * for additional info. */ public EmailIntent(@NonNull Fragment fragment) { super(fragment); } /** * Methods ===================================================================================== */ /** * Same as {@link #to(String)} for resource id. * * @param resId Resource id of the desired e-mail address. */ public EmailIntent to(@StringRes int resId) { return to(obtainString(resId)); } /** * Appends the given <var>address</var> to the current <b>primary</b> e-mail addresses to which * will be e-mail message send. * <p> * <b>Note</b>, that only valid e-mail address will be added. * * @param address The desired e-mail address to add. * @return This intent builder to allow methods chaining. * @see #to(String...) * @see #addresses() */ public EmailIntent to(@NonNull String address) { ensureAddresses(1); appendEmailAddress(mAddresses, address); return this; } /** * Same as {@link #to(List)} for array of addresses. * * @param addresses The desired array of e-mail addresses to add. */ public EmailIntent to(@NonNull String... addresses) { return to(Arrays.asList(addresses)); } /** * Appends the given set of <var>addresses</var> to the current <b>primary</b> e-mail addresses * to which will be e-mail message send. * <p> * <b>Note</b>, that only valid e-mail addresses will be added. * * @param addresses The desired set of e-mail addresses to add. * @return This intent builder to allow methods chaining. * @see #addresses() */ public EmailIntent to(@NonNull List<String> addresses) { ensureAddresses(addresses.size()); appendEmailAddresses(mAddresses, addresses); return this; } /** * Ensures that the list with addresses is properly initialized. * * @param initialSize Initial capacity for the list. */ private void ensureAddresses(int initialSize) { if (mAddresses == null) mAddresses = new ArrayList<>(initialSize); } /** * Returns the list with valid <b>primary</b> e-mail addresses. * * @return List with e-mail addresses specified via one of <b>to(...)</b> methods or * {@link Collections#EMPTY_LIST} if there were no addresses specified yet. * @see #to(int) * @see #to(String) * @see #to(String...) */ @NonNull @SuppressWarnings("unchecked") public List<String> addresses() { return mAddresses != null ? new ArrayList<>(mAddresses) : Collections.EMPTY_LIST; } /** * Clears the list with addresses specified via one of {@code to(...)} methods. * * @return This intent builder to allow methods chaining. * @see #to(int) * @see #to(String) * @see #to(String...) * @see #to(List) * @see #addresses() */ public EmailIntent clearAddresses() { if (mAddresses != null) { mAddresses.clear(); this.mAddresses = null; } return this; } /** * Same as {@link #cc(String)} for resource id. * * @param resId Resource id of the desired e-mail address. * @see #cc(String...) * @see #ccAddresses() */ public EmailIntent cc(@StringRes int resId) { return cc(obtainString(resId)); } /** * Appends the given <var>address</var> to the current <b>carbon copy</b> e-mail addresses. * See {@link Intent#EXTRA_CC} for more info. * <p> * <b>Note</b>, that only valid e-mail address will be added. * * @param address The desired e-mail address to add. * @return This intent builder to allow methods chaining. * @see #cc(int) * @see #cc(String...) * @see #ccAddresses() */ public EmailIntent cc(@NonNull String address) { ensureCcAddresses(1); appendEmailAddress(mCcAddresses, address); return this; } /** * Same as {@link #cc(List)} for array of addresses. * * @param addresses The desired array of e-mail addresses to add. */ public EmailIntent cc(@NonNull String... addresses) { return cc(Arrays.asList(addresses)); } /** * Appends the given set of <var>addresses</var> to the current <b>carbon copy</b> e-mail addresses. * See {@link Intent#EXTRA_CC} for more info. * <p> * <b>Note</b>, that only valid e-mail addresses will be added. * * @param addresses The desired set of e-mail addresses to add. * @return This intent builder to allow methods chaining. * @see #cc(int) * @see #cc(String) * @see #ccAddresses() */ public EmailIntent cc(@NonNull List<String> addresses) { ensureCcAddresses(addresses.size()); appendEmailAddresses(mCcAddresses, addresses); return this; } /** * Ensures that the list with <b>carbon-copy</b> addresses is properly initialized. * * @param initialSize Initial capacity for the list. */ private void ensureCcAddresses(int initialSize) { if (mCcAddresses == null) mCcAddresses = new ArrayList<>(initialSize); } /** * Returns the list with valid <b>carbon copy</b> e-mail addresses. * * @return List with e-mail addresses specified via one of <b>cc(...)</b> methods or * {@link Collections#EMPTY_LIST} if there were no addresses specified yet. * @see #cc(int) * @see #cc(String) * @see #cc(String...) */ @NonNull @SuppressWarnings("unchecked") public List<String> ccAddresses() { return mCcAddresses != null ? new ArrayList<>(mCcAddresses) : Collections.EMPTY_LIST; } /** * Clears the list with <b>carbon-copy</b> addresses specified via one of {@code cc(...)} methods. * * @return This intent builder to allow methods chaining. * @see #cc(int) * @see #cc(String) * @see #cc(String...) * @see #cc(List) * @see #ccAddresses() */ public EmailIntent clearCcAddresses() { if (mCcAddresses != null) { mCcAddresses.clear(); this.mCcAddresses = null; } return this; } /** * Same as {@link #bcc(String)} for resource id. * * @param resId Resource id of the desired e-mail address. * @see #bcc(String...) * @see #bccAddresses() */ public EmailIntent bcc(@StringRes int resId) { return bcc(obtainString(resId)); } /** * Appends the given <var>address</var> to the current <b>blind carbon copy</b> e-mail addresses. * See {@link Intent#EXTRA_BCC} for more info. * <p> * <b>Note</b>, that only valid e-mail address will be added. * * @param address The desired e-mail address to add. * @return This intent builder to allow methods chaining. * @see #bcc(int) * @see #bcc(String...) * @see #bccAddresses() */ public EmailIntent bcc(@NonNull String address) { ensureBccAddresses(1); appendEmailAddress(mBccAddresses, address); return this; } /** * Same as {@link #bcc(List)} for array of addresses. * * @param addresses The desired array of e-mail addresses to add. */ public EmailIntent bcc(@NonNull String... addresses) { return bcc(Arrays.asList(addresses)); } /** * Appends the given set of <var>addresses</var> to the current <b>blind carbon copy</b> e-mail * addresses. See {@link Intent#EXTRA_CC} for more info. * <p> * <b>Note</b>, that only valid e-mail addresses will be added. * * @param addresses The desired set of e-mail addresses to add. * @return This intent builder to allow methods chaining. * @see #bccAddresses() */ public EmailIntent bcc(@NonNull List<String> addresses) { ensureBccAddresses(addresses.size()); appendEmailAddresses(mBccAddresses, addresses); return this; } /** * Ensures that the list with <b>blind-carbon-copy</b> addresses is properly initialized. * * @param initialSize Initial capacity for the list. */ private void ensureBccAddresses(int initialSize) { if (mBccAddresses == null) mBccAddresses = new ArrayList<>(initialSize); } /** * Returns the list with valid <b>blind carbon copy</b> e-mail addresses. * * @return List with e-mail addresses specified via one of <b>bcc(...)</b> methods or * {@link Collections#EMPTY_LIST} if there were no addresses specified yet. * @see #bcc(int) * @see #bcc(String) * @see #bcc(String...) */ @NonNull @SuppressWarnings("unchecked") public List<String> bccAddresses() { return mBccAddresses != null ? new ArrayList<>(mBccAddresses) : Collections.EMPTY_LIST; } /** * Clears the list with <b>blind-carbon-copy</b> addresses specified via one of {@code bcc(...)} methods. * * @return This intent builder to allow methods chaining. * @see #bcc(int) * @see #bcc(String) * @see #bcc(String...) * @see #bcc(List) * @see #bccAddresses() */ public EmailIntent clearBccAddresses() { if (mBccAddresses != null) { mBccAddresses.clear(); this.mBccAddresses = null; } return this; } /** * Same as {@link #subject(CharSequence)} for resource id. * * @param resId Resource id of the desired subject text. */ public EmailIntent subject(@StringRes int resId) { return subject(obtainText(resId)); } /** * Set a subject for e-mail to send. See {@link Intent#EXTRA_SUBJECT} for more info. * * @param subject The desired subject text. * @return This intent builder to allow methods chaining. * @see #subject() */ public EmailIntent subject(@NonNull CharSequence subject) { this.mSubject = subject; return this; } /** * Returns the subject for e-mail to send. * * @return Subject of e-mail or empty text if not specified yet. * @see #subject(CharSequence) */ @NonNull public CharSequence subject() { return mSubject != null ? mSubject : ""; } /** * Same as {@link #message(CharSequence)} for resource id. * * @param resId Resource id of the desired e-mail message. */ public EmailIntent message(@StringRes int resId) { return message(obtainText(resId)); } /** * Sets a message for e-mail to send. * * @param message The desired message text. * @return This intent builder to allow methods chaining. * @see #message() */ public EmailIntent message(@NonNull CharSequence message) { this.mMessage = message; return this; } /** * Returns the message for e-mail to send. * * @return Message of e-mail or empty text if not specified yet. * @see #message(CharSequence) */ @NonNull public CharSequence message() { return mMessage != null ? mMessage : ""; } /** */ @Override protected void ensureCanBuildOrThrow() { super.ensureCanBuildOrThrow(); if (mAddresses == null) { throw cannotBuildIntentException("No e-mail address/-es specified."); } } /** */ @NonNull @Override protected Intent onBuild() { final Intent intent = new Intent(Intent.ACTION_SENDTO, createUri(mAddresses)); intent.putExtra(Intent.EXTRA_SUBJECT, mSubject); intent.putExtra(Intent.EXTRA_TEXT, mMessage); if (mCcAddresses != null) { intent.putExtra(Intent.EXTRA_CC, addressesToArray(mCcAddresses)); } if (mBccAddresses != null) { intent.putExtra(Intent.EXTRA_BCC, addressesToArray(mBccAddresses)); } return intent; } /** * Creates an URI specific for the {@link Intent#ACTION_SENDTO} intent action * from the given set of e-mails. * * @param addresses List with e-mail addresses. * @return Created URI containing the specified addresses or {@code null} if the given list of * addresses is empty. */ @Nullable protected static Uri createUri(@NonNull List<String> addresses) { final int n = addresses.size(); if (n == 0) return null; final StringBuilder data = new StringBuilder(n * 15); for (int i = 0; i < n; i++) { data.append(addresses.get(i)); if (i < (n - 1)) { data.append(","); } } return Uri.fromParts(URI_SCHEME, data.toString(), null); } /** * Transforms the specified list of addresses into array. * * @param addresses The list of addresses to be transformed. * @return Array of same size as the specified addresses and also with the same content. */ private static String[] addressesToArray(List<String> addresses) { final String[] addressesArray = new String[addresses.size()]; addresses.toArray(addressesArray); return addressesArray; } /** */ @Override protected boolean onStart(@NonNull Intent intent) { startActivity(Intent.createChooser(intent, mDialogTitle)); return true; } /** * Appends the given <var>addresses</var> into the given <var>list</var>. * * @param list The list into which append the addresses. * @param addresses Addresses to append. * otherwise, same instance with appended addresses. */ private static void appendEmailAddresses(List<String> list, List<String> addresses) { if (addresses.size() > 0) { for (String address : addresses) { appendEmailAddress(list, address); } } } /** * Appends the given <var>address</var> into the given <var>list</var>. * * @param list The list into which append the address. * @param address Address to append. * otherwise, same instance with appended address. */ static void appendEmailAddress(List<String> list, String address) { if (!EMAIL_MATCHER.reset(address).matches()) { Log.e(TAG, "Invalid e-mail address('" + address + "') specified."); return; } list.add(address); } /** * Inner classes =============================================================================== */ }