java_lang_programming.com.android_media_demo.article94.java.ImageDecoderActivity.java Source code

Java tutorial

Introduction

Here is the source code for java_lang_programming.com.android_media_demo.article94.java.ImageDecoderActivity.java

Source

/**
 * Copyright (C) 2017 Programming Java Android Development Project
 * Programming Java is
 * <p>
 * http://java-lang-programming.com/ja/articles/94
 * <p>
 * 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
 * <p>
 * http://www.apache.org/licenses/LICENSE-2.0
 * <p>
 * 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 java_lang_programming.com.android_media_demo.article94.java;

import android.Manifest;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.ImageDecoder;
import android.graphics.Matrix;
import android.graphics.Point;
import android.graphics.Rect;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import android.os.ParcelFileDescriptor;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.media.ExifInterface;
import android.support.v4.app.ActivityCompat;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.Toolbar;
import android.util.Log;
import android.util.Size;
import android.view.Display;
import android.view.WindowManager;
import android.widget.Button;
import android.widget.CheckBox;
import android.widget.ImageView;
import android.widget.TextView;
import android.widget.Toast;

import java.io.FileDescriptor;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.util.Collections;
import java.util.LinkedList;
import java.util.List;

import java_lang_programming.com.android_media_demo.ImageSelectionDemoActivity;
import java_lang_programming.com.android_media_demo.R;

/**
 * Activity for ImageDecoder Sample
 */
public class ImageDecoderActivity extends AppCompatActivity {

    private final static int REQUEST_CODE_CHOOSER = 101;

    /**
     * Id to identify a READ_EXTERNAL_STORAGE permission request.
     */
    private static final int REQUEST_READ_EXTERNAL_STORAGE = 0;

    public static final List<String> types = Collections.unmodifiableList(new LinkedList<String>() {
        {
            add("image/jpeg");
            add("image/jpg");
            add("image/png");
        }
    });

    /**
     * Permissions required to read external storage.
     */
    private static String[] PERMISSION_READ_EXTERNAL_STORAGE = { Manifest.permission.READ_EXTERNAL_STORAGE };

    private ImageView selectedImage;
    private TextView selectedImageInfo;
    private CheckBox checkedResize;
    private CheckBox checkedCrop;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_image_decoder);
        Toolbar toolbar = findViewById(R.id.toolbar);
        setSupportActionBar(toolbar);

        selectedImage = findViewById(R.id.selected_image);
        selectedImageInfo = findViewById(R.id.selected_image_info);
        checkedResize = findViewById(R.id.ck_resize);
        checkedCrop = findViewById(R.id.ck_crop);
        Button btnSelectImage = findViewById(R.id.btn_select_image);
        btnSelectImage.setOnClickListener(v -> checkPermission());
    }

    /**
     * Called when the '???' button is clicked.
     */
    private void checkPermission() {
        if (ActivityCompat.checkSelfPermission(this,
                Manifest.permission.READ_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
            // READ_EXTERNAL_STORAGE permission has not been granted.
            requestExternalStoragePermission();
        } else {
            startExternalAppSelectableImage();
        }
    }

    /**
     * Requests the READ_EXTERNAL_STORAGE permission.
     * the permission is requested directly.
     */
    private void requestExternalStoragePermission() {
        // Contact permissions have not been granted yet. Request them directly.
        ActivityCompat.requestPermissions(this, PERMISSION_READ_EXTERNAL_STORAGE, REQUEST_READ_EXTERNAL_STORAGE);
    }

    /**
     * start ExternalApps if the required READ_EXTERNAL_STORAGE permission has been granted.
     */
    private void startExternalAppSelectableImage() {
        Intent intent = new Intent(Intent.ACTION_GET_CONTENT);

        // Filter to only show results that can be "opened", such as a
        // file (as opposed to a list of contacts or timezones)
        intent.addCategory(Intent.CATEGORY_OPENABLE);
        intent.setType("image/*");
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
            intent.putExtra(Intent.EXTRA_MIME_TYPES, types.toArray());
        }
        startActivityForResult(Intent.createChooser(intent, null), ImageSelectionDemoActivity.REQUEST_CODE_CHOOSER);
    }

    @Override
    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions,
            @NonNull int[] grantResults) {
        super.onRequestPermissionsResult(requestCode, permissions, grantResults);
        switch (requestCode) {
        case (REQUEST_READ_EXTERNAL_STORAGE):
            if (verifyPermissions(grantResults)) {
                startExternalAppSelectableImage();
            } else {
                Toast.makeText(this, getString(R.string.permissions_not_granted), Toast.LENGTH_LONG).show();
            }
            break;
        default:
            super.onRequestPermissionsResult(requestCode, permissions, grantResults);
            break;
        }
    }

    /**
     * Check that all given permissions have been granted by verifying that each entry in the
     * given array is of the value {@link PackageManager#PERMISSION_GRANTED}.
     */
    public boolean verifyPermissions(int[] grantResults) {
        // At least one result must be checked.
        if (grantResults.length < 1) {
            return false;
        }

        // Verify that each required permission has been granted, otherwise return false.
        for (int result : grantResults) {
            if (result != PackageManager.PERMISSION_GRANTED) {
                return false;
            }
        }
        return true;
    }

    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        super.onActivityResult(requestCode, resultCode, data);
        switch (requestCode) {
        case (REQUEST_CODE_CHOOSER):
            if (resultCode != RESULT_OK || data.getData() == null) {
                Toast.makeText(this, getString(R.string.image_unselected_message), Toast.LENGTH_LONG).show();
                return;
            }
            Bitmap bitmap = null;
            // P ?
            if (Build.VERSION.SDK_INT == Build.VERSION_CODES.O_MR1) {
                Log.d("ImageDecoderActivity", "ImageDecoder");
                StringBuilder msg = new StringBuilder();
                try {
                    //                        bitmap = ImageDecoder.decodeBitmap(ImageDecoder.createSource(getContentResolver(), data.getData()));
                    bitmap = ImageDecoder.decodeBitmap(
                            ImageDecoder.createSource(getContentResolver(), data.getData()),
                            new ImageDecoder.OnHeaderDecodedListener() {
                                @Override
                                public void onHeaderDecoded(ImageDecoder imageDecoder,
                                        ImageDecoder.ImageInfo imageInfo, ImageDecoder.Source source) {
                                    if (checkedResize.isChecked()) {
                                        Size size = imageInfo.getSize();
                                        imageDecoder.setResize(size.getWidth() * 2, size.getHeight() * 2);
                                    }

                                    if (checkedCrop.isChecked()) {
                                        Size size = imageInfo.getSize();
                                        imageDecoder.setCrop(new Rect(0, 0, size.getWidth(), size.getHeight() / 2));
                                    }

                                    msg.append("ImageDecoder?bitmap??????\n");
                                    msg.append("? : " + imageInfo.getSize() + "\n");
                                    msg.append("? : " + imageInfo.getMimeType() + "\n");
                                    msg.append(" : " + imageInfo.isAnimated() + "\n");
                                }
                            });
                } catch (IOException e) {
                    e.printStackTrace();
                }
                selectedImageInfo.setText(msg.toString());
                // ?
            } else {
                Log.d("ImageDecoderActivity", "BitmapFactory");
                bitmap = getBitmap(getApplicationContext(), data.getData());
                selectedImageInfo.setText("BitmapFactory?bitmap??????");
            }

            if (bitmap != null) {
                selectedImage.setImageBitmap(bitmap);
            }
            break;
        default:
            break;
        }
    }

    /**
     * ???????
     *
     * @param uri ?Uri
     * @return ?????
     */
    private int getOrientation(@NonNull Uri uri) {
        int orientation = ExifInterface.ORIENTATION_UNDEFINED;
        InputStream in = null;
        try {
            in = getContentResolver().openInputStream(uri);
            if (in == null)
                return orientation;
            ExifInterface exifInterface = new ExifInterface(in);
            orientation = exifInterface.getAttributeInt(ExifInterface.TAG_ORIENTATION,
                    ExifInterface.ORIENTATION_UNDEFINED);
        } catch (IOException e) {
            e.getStackTrace();
        } finally {
            if (in != null) {
                try {
                    in.close();
                } catch (IOException ignored) {
                }
            }
        }
        return orientation;
    }

    /**
     * ????
     *
     * @param exifOrientation ???
     * @return ??
     */
    public int getRotation(int exifOrientation) {
        int rotation;
        switch (exifOrientation) {
        case ExifInterface.ORIENTATION_ROTATE_90:
        case ExifInterface.ORIENTATION_TRANSPOSE:
            rotation = 90;
            break;
        case ExifInterface.ORIENTATION_ROTATE_180:
        case ExifInterface.ORIENTATION_FLIP_VERTICAL:
            rotation = 180;
            break;
        case ExifInterface.ORIENTATION_ROTATE_270:
        case ExifInterface.ORIENTATION_TRANSVERSE:
            rotation = 270;
            break;
        default:
            rotation = 0;
        }
        return rotation;
    }

    /**
     * Bitmap??
     *
     * @param context 
     * @param uri     ?Uri
     * @return Bitmap
     */
    private @Nullable Bitmap getBitmap(@NonNull Context context, @NonNull Uri uri) {
        final ParcelFileDescriptor parcelFileDescriptor;
        try {
            parcelFileDescriptor = context.getContentResolver().openFileDescriptor(uri, "r");
        } catch (FileNotFoundException e) {
            e.getStackTrace();
            return null;
        }

        final FileDescriptor fileDescriptor;
        if (parcelFileDescriptor != null) {
            fileDescriptor = parcelFileDescriptor.getFileDescriptor();
        } else {
            // ParcelFileDescriptor was null for given Uri: [" + mInputUri + "]"
            return null;
        }

        final BitmapFactory.Options options = new BitmapFactory.Options();
        options.inJustDecodeBounds = true;
        BitmapFactory.decodeFileDescriptor(fileDescriptor, null, options);
        if (options.outWidth == -1 || options.outHeight == -1) {
            // "Bounds for bitmap could not be retrieved from the Uri: [" + mInputUri + "]"
            return null;
        }

        int orientation = getOrientation(uri);
        int rotation = getRotation(orientation);

        Matrix transformMatrix = new Matrix();
        transformMatrix.setRotate(rotation);

        // ???
        WindowManager wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
        Display display = wm.getDefaultDisplay();

        Point size = new Point();
        display.getSize(size);
        int width = size.x;
        int height = size.y;

        int reqWidth = Math.min(width, options.outWidth);
        int reqHeight = Math.min(height, options.outHeight);

        options.inSampleSize = calculateInSampleSize(options, reqWidth, reqHeight);
        options.inJustDecodeBounds = false;

        Bitmap decodeSampledBitmap = null;

        boolean decodeAttemptSuccess = false;
        while (!decodeAttemptSuccess) {
            try {
                decodeSampledBitmap = BitmapFactory.decodeFileDescriptor(fileDescriptor, null, options);
                decodeAttemptSuccess = true;
            } catch (OutOfMemoryError error) {
                Log.e("", "doInBackground: BitmapFactory.decodeFileDescriptor: ", error);
                options.inSampleSize *= 2;
            }
        }

        // ??
        decodeSampledBitmap = transformBitmap(decodeSampledBitmap, transformMatrix);

        return decodeSampledBitmap;
    }

    public int calculateInSampleSize(@NonNull BitmapFactory.Options options, int reqWidth, int reqHeight) {
        // Raw height and width of image
        final int height = options.outHeight;
        final int width = options.outWidth;
        int inSampleSize = 1;

        if (height > reqHeight || width > reqWidth) {
            // Calculate the largest inSampleSize value that is a power of 2 and keeps both
            // height and width lower or equal to the requested height and width.
            while ((height / inSampleSize) > reqHeight || (width / inSampleSize) > reqWidth) {
                inSampleSize *= 2;
            }
        }
        return inSampleSize;
    }

    public Bitmap transformBitmap(@NonNull Bitmap bitmap, @NonNull Matrix transformMatrix) {
        try {
            Bitmap converted = Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(),
                    transformMatrix, true);
            if (!bitmap.sameAs(converted)) {
                bitmap = converted;
            }
        } catch (OutOfMemoryError error) {
            Log.e("", "transformBitmap: ", error);
        }
        return bitmap;
    }
}