com.google.android.apps.forscience.whistlepunk.PictureUtils.java Source code

Java tutorial

Introduction

Here is the source code for com.google.android.apps.forscience.whistlepunk.PictureUtils.java

Source

/*
 *  Copyright 2016 Google Inc. All Rights Reserved.
 *
 *  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.google.android.apps.forscience.whistlepunk;

import android.Manifest;
import android.app.Activity;
import android.content.ActivityNotFoundException;
import android.content.ClipData;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.media.MediaScannerConnection;
import android.net.Uri;
import android.os.Build;
import android.os.Environment;
import android.provider.MediaStore;
import android.support.v4.content.FileProvider;
import android.text.TextUtils;
import android.util.Log;
import android.webkit.MimeTypeMap;

import java.io.File;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Date;

/**
 * Static picture functions shared across many parts of the app.
 */
public class PictureUtils {
    public static final String TAG = "PictureUtils";

    // Links a photo-taking request intent with the onActivityResult by requestType.
    public static final int REQUEST_TAKE_PHOTO = 1;
    public static final int PERMISSIONS_WRITE_EXTERNAL_STORAGE = 2;
    public static final int PERMISSIONS_CAMERA = 3;

    private static final String PICTURES_DIR_NAME = "ScienceJournal";
    private static final String PICTURE_NAME_TEMPLATE = "Picture_%s.jpg";

    // From http://developer.android.com/training/camera/photobasics.html.
    public static File createImageFile(long timestamp) throws IOException {
        // Create an image file name
        String imageDate = new SimpleDateFormat("yyyyMMdd-HHmmss").format(new Date(timestamp));
        String imageFileName = String.format(PICTURE_NAME_TEMPLATE, imageDate);
        File storageDir = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES),
                PICTURES_DIR_NAME);
        if (!storageDir.exists()) {
            storageDir.mkdirs();
        }
        File imageFile = new File(storageDir, imageFileName);
        return imageFile;
    }

    /**
     * Scan the file when adding or deleting so that media scanner aware apps like Gallery apps can
     * properly index the file.
     */
    public static void scanFile(String photoPath, Context context) {
        MediaScannerConnection.scanFile(context, new String[] { photoPath }, null,
                new MediaScannerConnection.OnScanCompletedListener() {
                    @Override
                    public void onScanCompleted(String path, Uri uri) {
                        Log.i(TAG, "Scanned " + path + ":");
                        Log.i(TAG, "-> uri=" + uri);
                    }
                });
    }

    public static String capturePictureLabel(final Activity activity) {
        return capturePictureLabel(activity, new IStartable() {
            @Override
            public void startActivityForResult(Intent intent, int requestCode) {
                activity.startActivityForResult(intent, requestCode);
            }
        });
    }

    public static String capturePictureLabel(final android.support.v4.app.Fragment fragment) {
        return capturePictureLabel(fragment.getActivity(), new IStartable() {
            @Override
            public void startActivityForResult(Intent intent, int requestCode) {
                fragment.startActivityForResult(intent, requestCode);
            }
        });
    }

    // From http://developer.android.com/training/camera/photobasics.html.
    private static String capturePictureLabel(Context context, IStartable startable) {
        // Starts a picture intent.
        Intent takePictureIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
        if (takePictureIntent.resolveActivity(context.getPackageManager()) != null) {
            File photoFile = null;
            try {
                photoFile = PictureUtils.createImageFile(
                        AppSingleton.getInstance(context).getSensorEnvironment().getDefaultClock().getNow());
            } catch (IOException ex) {
                if (Log.isLoggable(TAG, Log.DEBUG)) {
                    Log.d(TAG, ex.getMessage());
                }
            }
            if (photoFile != null) {
                Uri photoUri = FileProvider.getUriForFile(context, context.getPackageName(), photoFile);
                takePictureIntent.putExtra(MediaStore.EXTRA_OUTPUT, photoUri);
                if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) {
                    // Needed to avoid security exception on KitKat.
                    takePictureIntent.setClipData(ClipData.newRawUri(null, photoUri));
                }
                takePictureIntent.addFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
                String pictureLabelPath = "file:" + photoFile.getAbsoluteFile();
                startable.startActivityForResult(takePictureIntent, REQUEST_TAKE_PHOTO);
                return pictureLabelPath;
            }
        }
        return null;
    }

    private interface IStartable {
        void startActivityForResult(Intent intent, int requestCode);
    }

    // Assumes that the Camera permission always requires external storage.
    public static void cameraPermissionGranted(Activity activity, boolean granted) {
        // Try to get the storage permission granted if it is not yet, so that all the
        // camera-related permissions requests happen at once.
        if (granted) {
            PermissionUtils.tryRequestingPermission(activity, Manifest.permission.WRITE_EXTERNAL_STORAGE,
                    PERMISSIONS_WRITE_EXTERNAL_STORAGE, true);
        }
    }

    public static void onRequestPermissionsResult(int requestCode, String permissions[], int[] grantResults,
            Activity activity) {
        boolean granted = grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED;
        switch (requestCode) {
        case PERMISSIONS_CAMERA:
            cameraPermissionGranted(activity, granted);
            return;
        case PERMISSIONS_WRITE_EXTERNAL_STORAGE:
            // Do nothing for now
            return;
        }
    }

    public static void launchExternalViewer(Activity activity, String fileUrl) {
        Intent intent = new Intent(Intent.ACTION_VIEW);
        String extension = MimeTypeMap.getFileExtensionFromUrl(fileUrl);
        String type = MimeTypeMap.getSingleton().getMimeTypeFromExtension(extension);
        if (!TextUtils.isEmpty(type)) {
            String filePath = fileUrl;
            if (filePath.startsWith("file:")) {
                filePath = filePath.substring("file:".length());
            }
            Uri photoUri = FileProvider.getUriForFile(activity, activity.getPackageName(), new File(filePath));
            intent.setDataAndType(photoUri, type);
            if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) {
                // Needed to avoid security exception on KitKat.
                intent.setClipData(ClipData.newRawUri(null, photoUri));
            }
            intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
            try {
                activity.startActivity(intent);
            } catch (ActivityNotFoundException e) {
                Log.e(TAG, "No activity found to handle this " + fileUrl + " type " + type);
            }
        } else {
            Log.w(TAG, "Could not find mime type for " + fileUrl);
        }
    }
}