com.almalence.googsharing.Thumbnail.java Source code

Java tutorial

Introduction

Here is the source code for com.almalence.googsharing.Thumbnail.java

Source

/*
 * Copyright (C) 2011 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.almalence.googsharing;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.File;
import java.io.FileDescriptor;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.net.URI;

import android.content.ContentResolver;
import android.content.ContentUris;
import android.database.Cursor;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.graphics.PorterDuff.Mode;
import android.graphics.PorterDuffXfermode;
import android.graphics.Rect;
import android.graphics.RectF;
import android.media.MediaMetadataRetriever;
import android.net.Uri;
import android.os.Build;
import android.os.Environment;
import android.provider.DocumentsContract.Document;
import android.provider.DocumentsContract;
import android.provider.DocumentsProvider;
import android.provider.MediaStore.Images;
import android.provider.MediaStore.Images.ImageColumns;
import android.provider.MediaStore.Video;
import android.provider.MediaStore.Video.VideoColumns;
import android.support.v4.provider.DocumentFile;
import android.util.Log;

/* <!-- +++
 import com.almalence.opencam_plus.PluginManagerBase;
 +++ --> */
//<!-- -+-
import com.almalence.opencam.PluginManagerBase;
//-+- -->

import com.almalence.util.Util;

public class Thumbnail {
    private static final String TAG = "Thumbnail";

    public static final String LAST_THUMB_FILENAME = "last_thumb";
    private static final int BUFSIZE = 4096;

    private Uri mUri;
    private Bitmap mBitmap;
    private Bitmap mFullBitmap;
    // whether this thumbnail is read from file
    private boolean mFromFile = false;

    private static ContentResolver mResolver = null;

    public static final String DCIM = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DCIM)
            .toString();
    public static final String DIRECTORY = DCIM + "/Camera";
    // Match the code in MediaProvider.computeBucketValues().
    public static final String BUCKET_ID = String.valueOf(DIRECTORY.toLowerCase().hashCode());

    public Thumbnail(Uri uri, Bitmap bitmap, Bitmap fullBitmap, int orientation) {
        mUri = uri;
        mBitmap = rotateImage(bitmap, orientation);
        if (fullBitmap != null)
            mFullBitmap = rotateImage(fullBitmap, orientation);
        if (mBitmap == null)
            throw new IllegalArgumentException("null bitmap");
    }

    public Uri getUri() {
        return mUri;
    }

    public Bitmap getBitmap() {
        return mBitmap;
    }

    public Bitmap getFullBitmap() {
        Media image = getLastImageThumbnail(mResolver);

        if (image == null)
            return null;

        Bitmap fullBitmap = null;

        try {
            fullBitmap = Images.Media.getBitmap(mResolver, image.uri);
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }

        mFullBitmap = null;
        System.gc();

        mUri = image.uri;
        mFullBitmap = rotateImage(fullBitmap, image.orientation);
        if (mFullBitmap == null)
            throw new IllegalArgumentException("null bitmap");

        return mFullBitmap;
    }

    public void setFromFile(boolean fromFile) {
        mFromFile = fromFile;
    }

    public boolean fromFile() {
        return mFromFile;
    }

    private static Bitmap rotateImage(Bitmap bitmap, int orientation) {
        if (orientation != 0) {
            // We only rotate the thumbnail once even if we get OOM.
            Matrix m = new Matrix();
            m.setRotate(orientation, bitmap.getWidth() * 0.5f, bitmap.getHeight() * 0.5f);

            try {
                Bitmap rotated = Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), m, true);
                // If the rotated bitmap is the original bitmap, then it
                // should not be recycled.
                if (rotated != bitmap)
                    bitmap.recycle();
                return rotated;
            } catch (Exception t) {
                Log.w(TAG, "Failed to rotate thumbnail", t);
            }
        }

        return bitmap;
    }

    // Stores the bitmap to the specified file.
    public void saveTo(File file) {
        FileOutputStream f = null;
        BufferedOutputStream b = null;
        DataOutputStream d = null;
        try {
            f = new FileOutputStream(file);
            b = new BufferedOutputStream(f, BUFSIZE);
            d = new DataOutputStream(b);
            d.writeUTF(mUri.toString());
            mBitmap.compress(Bitmap.CompressFormat.JPEG, 90, d);
            d.close();
        } catch (IOException e) {
            Log.e(TAG, "Fail to store bitmap. path=" + file.getPath(), e);
        } finally {
            Util.closeSilently(f);
            Util.closeSilently(b);
            Util.closeSilently(d);
        }
    }

    // Loads the data from the specified file.
    // Returns null if failure.
    public static Thumbnail loadFrom(File file) {
        Uri uri = null;
        Bitmap bitmap = null;
        FileInputStream f = null;
        BufferedInputStream b = null;
        DataInputStream d = null;
        try {
            f = new FileInputStream(file);
            b = new BufferedInputStream(f, BUFSIZE);
            d = new DataInputStream(b);
            uri = Uri.parse(d.readUTF());
            bitmap = BitmapFactory.decodeStream(d);
            d.close();
        } catch (IOException e) {
            Log.i(TAG, "Fail to load bitmap. " + e);

            return null;
        } finally {
            Util.closeSilently(f);
            Util.closeSilently(b);
            Util.closeSilently(d);
        }

        Thumbnail thumbnail = createThumbnail(uri, bitmap, null, 0);
        if (thumbnail != null)
            thumbnail.setFromFile(true);

        return thumbnail;
    }

    public static Thumbnail getLastThumbnail(ContentResolver resolver) {
        mResolver = resolver;
        Media image = getLastImageThumbnail(resolver);
        Media video = getLastVideoThumbnail(resolver);

        if (image == null && video == null)
            return null;

        Bitmap bitmap = null;
        Media lastMedia = null;

        try {
            // If there is only image or video, get its thumbnail. If both
            // exist,
            // get the thumbnail of the one that is newer.
            if (image != null && (video == null || image.dateTaken >= video.dateTaken)) {
                bitmap = Images.Thumbnails.getThumbnail(resolver, image.id, Images.Thumbnails.MICRO_KIND, null);
                lastMedia = image;
            } else if (video != null) {
                bitmap = Video.Thumbnails.getThumbnail(resolver, video.id, Video.Thumbnails.MICRO_KIND, null);
                lastMedia = video;
            }
        } catch (Exception ex) {
            Log.e("getLastThumbnail", "createThumbnail exception " + ex.getMessage());
            return null;
        }

        try {
            return createThumbnail(lastMedia.uri, bitmap, null, lastMedia.orientation);
        } catch (Exception ex) {
            Log.e("getLastThumbnail", "createThumbnail exception " + ex.getMessage());
            return null;
        }
    }

    private static class Media {
        public Media(long id, int orientation, long dateTaken, Uri uri) {
            this.id = id;
            this.orientation = orientation;
            this.dateTaken = dateTaken;
            this.uri = uri;
        }

        public final long id;
        public final int orientation;
        public final long dateTaken;
        public final Uri uri;
    }

    public static Bitmap getRoundedCornerBitmap(Bitmap bitmap, int size, int pixels) {
        final int side = Math.min(bitmap.getWidth(), bitmap.getHeight());

        final Bitmap bitmapCropped = Bitmap.createBitmap(bitmap, (bitmap.getWidth() - side) / 2,
                (bitmap.getHeight() - side) / 2, side, side);

        final Bitmap output = Bitmap.createBitmap(size, size, Bitmap.Config.ARGB_8888);

        Canvas canvas = new Canvas(output);

        final int color = 0xffffffff;
        final Paint paint = new Paint();
        final Rect rectSrc = new Rect(0, 0, bitmapCropped.getWidth(), bitmapCropped.getHeight());
        final Rect rect = new Rect(6, 6, output.getWidth() - 6, output.getHeight() - 6);
        final RectF rectF = new RectF(rect);
        final RectF rectFBorder = new RectF(0, 0, output.getWidth(), output.getHeight());
        final float roundPx = pixels;

        paint.setAntiAlias(true);
        canvas.drawARGB(0, 0, 0, 0);
        paint.setColor(color);
        canvas.drawRoundRect(rectF, roundPx, roundPx, paint);

        paint.setXfermode(new PorterDuffXfermode(Mode.SRC_IN));
        canvas.drawBitmap(bitmapCropped, rectSrc, rect, paint);

        paint.setXfermode(new PorterDuffXfermode(Mode.DST_ATOP));
        canvas.drawRoundRect(rectFBorder, roundPx, roundPx, paint);

        return output;
    }

    public static String getName() {
        String name = "";
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
            DocumentFile saveDir = PluginManagerBase.getSaveDirNew(false);
            if (saveDir != null) {
                if (!saveDir.canWrite()) {
                    saveDir = PluginManagerBase.getSaveDirNew(true);
                }

                // Try to build max deep file path
                //            DocumentFile parentFile = saveDir.getParentFile();
                //            name = saveDir.getName();
                //            while (parentFile != null)
                //            {
                //               name = parentFile.getName() + "/" + name;
                //               parentFile = parentFile.getParentFile(); 
                //            }
                //            
                //            // If we able to get File object, than get path from it
                //            try
                //            {
                //               File file = new File(URI.create(saveDir.getUri().toString()));
                //               name = file.getAbsolutePath();
                //            } catch (Exception e)
                //            {
                //            } finally
                //            {
                //            }

                // If we able to get File object, than get path from it.
                // fileObject should not be null for files on phone memory.
                File fileObject = Util.getFileFromDocumentFile(saveDir);
                if (fileObject != null) {
                    name = fileObject.getAbsolutePath();
                } else {
                    // This case should typically happen for files saved to SD
                    // card.
                    name = Util.getAbsolutePathFromDocumentFile(saveDir);
                }

            }
        } else {
            File saveDir = PluginManagerBase.getSaveDir(false);
            if (!saveDir.canWrite()) {
                saveDir = PluginManagerBase.getSaveDir(true);
            }
            name = saveDir.getAbsolutePath();
        }

        return name;
    }

    public static Media getLastImageThumbnail(ContentResolver resolver) {
        Media internalMedia = null;
        Media externalMedia = null;

        String name = getName();

        try {
            Uri baseUri = Images.Media.INTERNAL_CONTENT_URI;

            Uri query = baseUri.buildUpon().appendQueryParameter("limit", "1").build();
            String[] projection = new String[] { ImageColumns._ID, ImageColumns.ORIENTATION,
                    ImageColumns.DATE_TAKEN };

            String selection = ImageColumns.DATA + " like '%" + name + "%' AND " + ImageColumns.MIME_TYPE
                    + "='image/jpeg'";
            String order = ImageColumns.DATE_TAKEN + " DESC," + ImageColumns._ID + " DESC";

            Cursor cursor = null;

            try {
                cursor = resolver.query(query, projection, selection, null, order);
                if (cursor != null && cursor.moveToFirst()) {
                    final long id = cursor.getLong(0);
                    internalMedia = new Media(id, cursor.getInt(1), cursor.getLong(2),
                            ContentUris.withAppendedId(baseUri, id));
                }
            } finally {
                if (cursor != null) {
                    cursor.close();
                }
            }
        } catch (Exception e) {

        }

        try {
            Uri baseUri = Images.Media.EXTERNAL_CONTENT_URI;
            Uri query = baseUri.buildUpon().appendQueryParameter("limit", "1").build();
            String[] projection = new String[] { ImageColumns._ID, ImageColumns.ORIENTATION,
                    ImageColumns.DATE_TAKEN };

            String selection = ImageColumns.DATA + " like '%" + name + "%' AND " + ImageColumns.MIME_TYPE
                    + "='image/jpeg'";
            String order = ImageColumns.DATE_TAKEN + " DESC," + ImageColumns._ID + " DESC";

            Cursor cursor = null;

            try {
                cursor = resolver.query(query, projection, selection, null, order);
                if (cursor != null && cursor.moveToFirst()) {
                    final long id = cursor.getLong(0);
                    externalMedia = new Media(id, cursor.getInt(1), cursor.getLong(2),
                            ContentUris.withAppendedId(baseUri, id));
                }
            } finally {
                if (cursor != null) {
                    cursor.close();
                }
            }
        } catch (Exception e) {

        }

        if (internalMedia == null) {
            return externalMedia;
        } else if (externalMedia == null) {
            return internalMedia;
        } else {
            return internalMedia.dateTaken > externalMedia.dateTaken ? internalMedia : externalMedia;
        }
    }

    public static Thumbnail createThumbnail(byte[] jpeg, int orientation, int inSampleSize, Uri uri) {
        // Create the thumbnail.
        BitmapFactory.Options options = new BitmapFactory.Options();
        options.inSampleSize = inSampleSize;
        Bitmap bitmap = BitmapFactory.decodeByteArray(jpeg, 0, jpeg.length, options);
        return createThumbnail(uri, bitmap, null, orientation);
    }

    private static Thumbnail createThumbnail(Uri uri, Bitmap bitmap, Bitmap fullBitmap, int orientation) {
        if (bitmap == null) {
            Log.e(TAG, "Failed to create thumbnail from null bitmap");
            return null;
        }
        try {
            return new Thumbnail(uri, bitmap, fullBitmap, orientation);
        } catch (IllegalArgumentException e) {
            Log.e(TAG, "Failed to construct thumbnail", e);
            return null;
        }
    }

    private static Media getLastVideoThumbnail(ContentResolver resolver) {

        Media internalMedia = null;
        Media externalMedia = null;

        String name = getName();

        try {
            Uri baseUri = Video.Media.INTERNAL_CONTENT_URI;

            Uri query = baseUri.buildUpon().appendQueryParameter("limit", "1").build();
            String[] projection = new String[] { VideoColumns._ID, VideoColumns.DATA, VideoColumns.DATE_TAKEN };

            String selection = VideoColumns.DATA + " like '%" + name + "%' AND " + VideoColumns.MIME_TYPE
                    + "='video/mp4'";
            String order = VideoColumns.DATE_TAKEN + " DESC," + VideoColumns._ID + " DESC";

            Cursor cursor = null;

            try {
                cursor = resolver.query(query, projection, selection, null, order);
                if (cursor != null && cursor.moveToFirst()) {
                    final long id = cursor.getLong(0);
                    internalMedia = new Media(id, 0, cursor.getLong(2), ContentUris.withAppendedId(baseUri, id));
                }
            } finally {
                if (cursor != null) {
                    cursor.close();
                }
            }
        } catch (Exception e) {

        }

        try {
            Uri baseUri = Video.Media.EXTERNAL_CONTENT_URI;
            Uri query = baseUri.buildUpon().appendQueryParameter("limit", "1").build();
            String[] projection = new String[] { VideoColumns._ID, VideoColumns.DATA, VideoColumns.DATE_TAKEN };

            String selection = VideoColumns.DATA + " like '%" + name + "%' AND " + VideoColumns.MIME_TYPE
                    + "='video/mp4'";
            String order = VideoColumns.DATE_TAKEN + " DESC," + VideoColumns._ID + " DESC";

            Cursor cursor = null;

            try {
                cursor = resolver.query(query, projection, selection, null, order);
                if (cursor != null && cursor.moveToFirst()) {
                    final long id = cursor.getLong(0);
                    externalMedia = new Media(id, 0, cursor.getLong(2), ContentUris.withAppendedId(baseUri, id));
                }
            } finally {
                if (cursor != null) {
                    cursor.close();
                }
            }
        } catch (Exception e) {

        }

        if (internalMedia == null) {
            return externalMedia;
        } else if (externalMedia == null) {
            return internalMedia;
        } else {
            return internalMedia.dateTaken > externalMedia.dateTaken ? internalMedia : externalMedia;
        }
    }

    public static Bitmap createVideoThumbnail(FileDescriptor fd, int targetWidth) {
        return createVideoThumbnail(null, fd, targetWidth);
    }

    public static Bitmap createVideoThumbnail(String filePath, int targetWidth) {
        return createVideoThumbnail(filePath, null, targetWidth);
    }

    private static Bitmap createVideoThumbnail(String filePath, FileDescriptor fd, int targetWidth) {
        Bitmap bitmap = null;
        MediaMetadataRetriever retriever = new MediaMetadataRetriever();
        try {
            if (filePath != null) {
                retriever.setDataSource(filePath);
            } else {
                retriever.setDataSource(fd);
            }
            bitmap = retriever.getFrameAtTime(-1);
        } catch (IllegalArgumentException ex) {
            // Assume this is a corrupt video file
        } catch (RuntimeException ex) {
            // Assume this is a corrupt video file.
        } finally {
            try {
                retriever.release();
            } catch (RuntimeException ex) {
                // Ignore failures while cleaning up.
            }
        }
        if (bitmap == null)
            return null;

        // Scale down the bitmap if it is bigger than we need.
        int width = bitmap.getWidth();
        int height = bitmap.getHeight();
        if (width > targetWidth) {
            float scale = (float) targetWidth / width;
            int w = Math.round(scale * width);
            int h = Math.round(scale * height);
            bitmap = Bitmap.createScaledBitmap(bitmap, w, h, true);
        }
        return bitmap;
    }
}