com.wit.android.support.content.intent.ImageIntent.java Source code

Java tutorial

Introduction

Here is the source code for com.wit.android.support.content.intent.ImageIntent.java

Source

/*
 * =================================================================================================
 *                    Copyright (C) 2014 Martin Albedinsky [Wolf-ITechnologies]
 * =================================================================================================
 *         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.wit.android.support.content.intent;

import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.net.Uri;
import android.os.Bundle;
import android.os.Environment;
import android.provider.MediaStore;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.v4.app.Fragment;
import android.util.Log;

import com.wit.android.support.content.MimeType;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;

/**
 * <h3>Class Overview</h3>
 * Intent builder specialized to create PICK IMAGE intents.
 *
 * @author Martin Albedinsky
 */
public class ImageIntent extends ContentIntent {

    /**
     * Interface ===================================================================================
     */

    /**
     * Constants ===================================================================================
     */

    /**
     * Log TAG.
     */
    private static final String TAG = "ImageIntent";

    /**
     * Flag indicating whether the output trough log-cat is enabled or not.
     */
    // private static final boolean LOG_ENABLED = true;

    /**
     * Flag indicating whether the debug output trough log-cat is enabled or not.
     */
    // private static final boolean DEBUG_ENABLED = true;

    /**
     * Flag to identify request code used to obtain image from gallery.
     */
    public static final int REQUEST_CODE_GALLERY = 0x5001;

    /**
     * Flag to identify request code used to obtain image using camera.
     */
    public static final int REQUEST_CODE_CAMERA = 0x5002;

    /**
     * Default format for image file name.
     * <p>
     * Constant value: <b>IMAGE_%s</b>
     */
    public static final String IMAGE_FILE_NAME_FORMAT = "IMAGE_%s";

    /**
     * Static members ==============================================================================
     */

    /**
     * Members =====================================================================================
     */

    /**
     * Camera provider item.
     */
    private ContentProviderItem mCameraProvider;

    /**
     * Constructors ================================================================================
     */

    /**
     * Creates a new instance of ImageIntent for the given <var>activity</var> context.
     * <p>
     * See {@link com.wit.android.support.content.intent.BaseIntent#BaseIntent(android.app.Activity)}
     * for additional info.
     */
    public ImageIntent(@NonNull Activity activity) {
        super(activity);
    }

    /**
     * Creates a new instance of GetImageIntent for the given <var>fragment</var> context.
     * <p>
     * See {@link com.wit.android.support.content.intent.BaseIntent#BaseIntent(android.support.v4.app.Fragment)}
     * for additional info.
     */
    public ImageIntent(@NonNull Fragment fragment) {
        super(fragment);
    }

    /**
     * Methods =====================================================================================
     */

    /**
     * Public --------------------------------------------------------------------------------------
     */

    /**
     * Creates a new instance of Intent with {@link Intent#ACTION_GET_CONTENT} and {@link MimeType#IMAGE}
     * MIME type.
     *
     * @return New intent instance.
     */
    @NonNull
    public static Intent createGalleryIntent() {
        return new Intent(Intent.ACTION_GET_CONTENT).setType(MimeType.IMAGE);
    }

    /**
     * Same as {@link #createCameraIntent(java.io.File)} with {@code null} for <var>outputFile</var>
     * parameter.
     */
    @NonNull
    public static Intent createCameraIntent() {
        return createCameraIntent((Uri) null);
    }

    /**
     * Same as {@link #createCameraIntent(android.net.Uri)} with <var>outputUri</var> created from
     * the given <var>outputFile</var>.
     *
     * @param outputFile A file used to crate Uri.
     * @see #createCameraIntent()
     */
    @NonNull
    public static Intent createCameraIntent(@Nullable File outputFile) {
        return createCameraIntent(outputFile != null ? Uri.fromFile(outputFile) : null);
    }

    /**
     * Creates a new instance of Intent with {@link MediaStore#ACTION_IMAGE_CAPTURE}.
     *
     * @param outputUri If not {@code null}, it will be attached to intent as {@link MediaStore#EXTRA_OUTPUT},
     *                  so when the result is received in for example {@link Activity#onActivityResult(int, int, android.content.Intent)},
     *                  the <var>outputUri</var> will address to a file which contains the currently
     *                  captured image if the camera provider's item was selected within <b>chooser dialog</b>
     *                  and user confirmed that captured image.
     * @return New intent instance.
     * @see #createCameraIntent(java.io.File)
     */
    @NonNull
    public static Intent createCameraIntent(@Nullable Uri outputUri) {
        final Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
        if (outputUri != null) {
            intent.putExtra(MediaStore.EXTRA_OUTPUT, outputUri);
        }
        return intent;
    }

    /**
     * Same as {@link #createImageFile(String)} with <var>fileName</var> in {@link #IMAGE_FILE_NAME_FORMAT}
     * format with the current time stamp provided by {@link #createContentFileTimeStamp() }.
     */
    @Nullable
    public static File createImageFile() {
        return createImageFile(String.format(IMAGE_FILE_NAME_FORMAT, createContentFileTimeStamp()));
    }

    /**
     * Same as {@link #createContentFile(String, String, String)} with <b>.jpg</b> as <var>fileType</var>
     * and {@link Environment#DIRECTORY_PICTURES} as <var>environmentDirectoryType</var>.
     *
     * @param fileName Desired name for the image file.
     * @see #createImageFile()
     */
    @Nullable
    public static File createImageFile(@NonNull String fileName) {
        return createContentFile(fileName, ".jpg", Environment.DIRECTORY_PICTURES);
    }

    /**
     * Same as {@link #processResultIntent(int, int, android.content.Intent, android.content.Context, ImageIntent.ImageOptions)}
     * with {@code null} <var>options</var>.
     */
    @Nullable
    public static Bitmap processResultIntent(int requestCode, int resultCode, @Nullable Intent data,
            @NonNull Context context) {
        return processResultIntent(requestCode, resultCode, data, context, null);
    }

    /**
     * Processes the given result <var>data</var> to obtain the requested Bitmap.
     * <p>
     * <b>Note</b>, that in case of {@link #REQUEST_CODE_CAMERA}, the obtained Bitmap will be only todo....
     * For full quality image pass an instance of Uri to {@link #output(android.net.Uri)}.
     *
     * @param requestCode The request code from {@link Activity#onActivityResult(int, int, android.content.Intent)} or
     *                    {@link android.support.v4.app.Fragment#onActivityResult(int, int, android.content.Intent)}.
     *                    Can be only one of {@link #REQUEST_CODE_CAMERA} or {@link #REQUEST_CODE_GALLERY}.
     * @param resultCode  The result code from {@link Activity#onActivityResult(int, int, android.content.Intent)} or
     *                    {@link android.support.v4.app.Fragment#onActivityResult(int, int, android.content.Intent)}.
     *                    If {@link Activity#RESULT_OK}, the passed <var>data</var> will be processed,
     *                    otherwise {@code null} will be returned.
     * @param data        The data from {@link Activity#onActivityResult(int, int, android.content.Intent)} or
     *                    {@link android.support.v4.app.Fragment#onActivityResult(int, int, android.content.Intent)}.
     * @param context     Current valid context.
     * @param options     Image options to adjust obtained bitmap.
     * @return Instance of Bitmap obtained from the given <var>data</var> Intent.
     */
    @Nullable
    public static Bitmap processResultIntent(int requestCode, int resultCode, @Nullable Intent data,
            @NonNull Context context, @Nullable ImageOptions options) {
        if (data != null) {
            switch (resultCode) {
            case Activity.RESULT_OK:
                switch (requestCode) {
                case REQUEST_CODE_GALLERY:
                    final Uri imageUri = data.getData();
                    Bitmap galleryImage = null;

                    if (imageUri != null) {
                        InputStream stream = null;
                        try {
                            stream = context.getContentResolver().openInputStream(imageUri);
                        } catch (Exception e) {
                            Log.e(TAG, "Unable to open image content: " + imageUri, e);
                        } finally {
                            if (stream != null) {
                                if (options != null) {
                                    // Get the dimensions of the returned bitmap.
                                    final BitmapFactory.Options bmOptions = new BitmapFactory.Options();
                                    bmOptions.inJustDecodeBounds = true;
                                    BitmapFactory.decodeStream(stream, null, bmOptions);
                                    final int bmWidth = bmOptions.outWidth;
                                    final int bmHeight = bmOptions.outHeight;

                                    // Compute how much to scale the bitmap.
                                    final int scaleFactor = Math.min(bmWidth / options.width,
                                            bmHeight / options.height);

                                    // Decode scaled bitmap.
                                    bmOptions.inJustDecodeBounds = false;
                                    bmOptions.inSampleSize = scaleFactor;
                                    bmOptions.inPurgeable = true;
                                    galleryImage = BitmapFactory.decodeStream(stream, null, bmOptions);
                                } else {
                                    galleryImage = BitmapFactory.decodeStream(stream);
                                }

                                try {
                                    stream.close();
                                } catch (IOException e) {
                                    Log.e(TAG, "Unable to close image content: " + imageUri, e);
                                }
                            }
                        }
                    }
                    return galleryImage;
                case REQUEST_CODE_CAMERA:
                    final Bundle extras = data.getExtras();
                    try {
                        final Bitmap cameraImage = (extras != null) ? (Bitmap) extras.get("data") : null;
                        if (cameraImage != null && options != null) {
                            return Bitmap.createScaledBitmap(cameraImage, options.width, options.height, false);
                        }
                        return cameraImage;
                    } catch (Exception e) {
                        Log.e(TAG, "Failed to retrieve captured image.", e);
                    }
                }
                break;
            case Activity.RESULT_CANCELED:
                // User canceled get image action.
                break;
            }
        }
        return null;
    }

    /**
     * Adds two default {@link com.wit.android.support.content.intent.ContentIntent.ContentProviderItem}s.
     * One for {@link #REQUEST_CODE_GALLERY} and second one for {@link #REQUEST_CODE_CAMERA}.
     */
    @Override
    public ImageIntent withDefaultProviders() {
        withProviders(
                new ContentProviderItem().name("Gallery").intent(createGalleryIntent())
                        .requestCode(REQUEST_CODE_GALLERY),
                mCameraProvider = new ContentProviderItem().name("Camera").intent(createCameraIntent())
                        .requestCode(REQUEST_CODE_CAMERA));
        if (mUri != null) {
            mCameraProvider.intent.putExtra(MediaStore.EXTRA_OUTPUT, mUri);
        }
        return this;
    }

    /**
     * Getters + Setters ---------------------------------------------------------------------------
     */

    /**
     * If the passed <var>uri</var> is not {@code null}, the current data (MIME) type will be
     * by default set to {@link MimeType#IMAGE}.
     */
    @Override
    public ContentIntent input(@Nullable Uri uri) {
        super.input(uri);
        if (uri != null) {
            this.mDataType = MimeType.IMAGE;
        }
        return this;
    }

    /**
     * Sets the output uri for image captured by camera.
     *
     * @param uri If not {@code null}, it will be attached to {@link com.wit.android.support.content.intent.ContentIntent.ContentProviderItem}
     *            holding intent with the {@link #REQUEST_CODE_CAMERA} request code, so when the camera
     *            provider's item will be selected within a <b>chooser dialog</b> and user confirms his
     *            captured photo, result about this action will be received in for example
     *            {@link Activity#onActivityResult(int, int, android.content.Intent)}. The passed
     *            <var>uri</var> will then address to a file which contains the currently captured
     *            image.
     * @return This intent builder to allow methods chaining.
     */
    @Override
    public ContentIntent output(@Nullable Uri uri) {
        if (mCameraProvider != null) {
            if (uri != null) {
                mCameraProvider.intent.putExtra(MediaStore.EXTRA_OUTPUT, uri);
            } else {
                mCameraProvider.intent.removeExtra(MediaStore.EXTRA_OUTPUT);
            }
        }
        return super.output(uri);
    }

    /**
     * Protected -----------------------------------------------------------------------------------
     */

    /**
     * Private -------------------------------------------------------------------------------------
     */

    /**
     * Inner classes ===============================================================================
     */

    /**
     * <h3>Class Overview</h3>
     * Simple options for {@link #processResultIntent(int, int, android.content.Intent, android.content.Context, ImageIntent.ImageOptions)}.
     *
     * @author Martin Albedinsky
     */
    public static class ImageOptions {

        /**
         * Members =================================================================================
         */

        /**
         * Dimensions to which should be obtained image bitmap re-sized.
         */
        int width, height;

        /**
         * Methods =================================================================================
         */

        /**
         * Sets the dimensions to which should be the obtained image bitmap re-sized.
         *
         * @param width  The desired image width to re-size to.
         * @param height The desired image height to re-size to.
         * @return This options instance.
         */
        public ImageOptions inSize(int width, int height) {
            this.width = width;
            this.height = height;
            return this;
        }
    }
}