org.opendatakit.survey.activities.MediaCaptureImageActivity.java Source code

Java tutorial

Introduction

Here is the source code for org.opendatakit.survey.activities.MediaCaptureImageActivity.java

Source

/*
 * Copyright (C) 2012-2013 University of Washington
 *
 * 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 org.opendatakit.survey.activities;

import android.app.Activity;
import android.content.ActivityNotFoundException;
import android.content.ContentValues;
import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
import android.provider.MediaStore.Audio;
import android.provider.MediaStore.Images;
import android.widget.Toast;

import org.apache.commons.io.FileUtils;
import org.opendatakit.demoAndroidCommonClasses.activities.BaseActivity;
import org.opendatakit.demoAndroidlibraryClasses.logging.WebLogger;
import org.opendatakit.demoAndroidlibraryClasses.consts.IntentConsts;
import org.opendatakit.demoAndroidlibraryClasses.utilities.MediaUtils;
import org.opendatakit.demoAndroidlibraryClasses.utilities.ODKFileUtils;
import org.opendatakit.survey.R;

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

/**
 * Simple shim for media interactions.
 *
 * @author mitchellsundt@gmail.com
 *
 */
public class MediaCaptureImageActivity extends BaseActivity {
    private static final String t = "MediaCaptureImageActivity";

    protected static final int ACTION_CODE = 1;
    private static final String MEDIA_CLASS = "image/";

    protected static final String TMP_EXTENSION = ".tmp.jpg";

    private static final String URI_FRAGMENT_NEW_FILE_BASE = "uriFragmentNewFileBase";
    private static final String HAS_LAUNCHED = "hasLaunched";
    private static final String AFTER_RESULT = "afterResult";
    private static final String ERROR_NO_FILE = "Media file does not exist! ";
    private static final String ERROR_COPY_FILE = "Media file copy failed! ";

    protected String appName = null;
    protected String tableId = null;
    protected String instanceId = null;
    protected String uriFragmentNewFileBase = null;
    protected String uriFragmentToMedia = null;
    protected String currentUriFragment = null;
    protected boolean afterResult = false;
    protected boolean hasLaunched = false;
    protected Intent launchIntent = null;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        Bundle extras = getIntent().getExtras();
        if (extras != null) {
            appName = extras.getString(IntentConsts.INTENT_KEY_APP_NAME);
            tableId = extras.getString(IntentConsts.INTENT_KEY_TABLE_ID);
            instanceId = extras.getString(IntentConsts.INTENT_KEY_INSTANCE_ID);
            uriFragmentToMedia = extras.getString(IntentConsts.INTENT_KEY_URI_FRAGMENT);
            currentUriFragment = extras.getString(IntentConsts.INTENT_KEY_CURRENT_URI_FRAGMENT);
            hasLaunched = extras.getBoolean(HAS_LAUNCHED);
            afterResult = extras.getBoolean(AFTER_RESULT);
            uriFragmentNewFileBase = extras.getString(URI_FRAGMENT_NEW_FILE_BASE);
        }

        if (savedInstanceState != null) {
            appName = savedInstanceState.getString(IntentConsts.INTENT_KEY_APP_NAME);
            tableId = savedInstanceState.getString(IntentConsts.INTENT_KEY_TABLE_ID);
            instanceId = savedInstanceState.getString(IntentConsts.INTENT_KEY_INSTANCE_ID);
            uriFragmentToMedia = savedInstanceState.getString(IntentConsts.INTENT_KEY_URI_FRAGMENT);
            currentUriFragment = extras.getString(IntentConsts.INTENT_KEY_CURRENT_URI_FRAGMENT);
            hasLaunched = savedInstanceState.getBoolean(HAS_LAUNCHED);
            afterResult = savedInstanceState.getBoolean(AFTER_RESULT);
            uriFragmentNewFileBase = savedInstanceState.getString(URI_FRAGMENT_NEW_FILE_BASE);
        }

        if (appName == null) {
            throw new IllegalArgumentException(
                    "Expected " + IntentConsts.INTENT_KEY_APP_NAME + " key in intent bundle. Not found.");
        }

        if (tableId == null) {
            throw new IllegalArgumentException(
                    "Expected " + IntentConsts.INTENT_KEY_TABLE_ID + " key in intent bundle. Not found.");
        }
        if (instanceId == null) {
            throw new IllegalArgumentException(
                    "Expected " + IntentConsts.INTENT_KEY_INSTANCE_ID + " key in intent bundle. Not found.");
        }

        if (uriFragmentToMedia == null) {
            if (uriFragmentNewFileBase == null) {
                throw new IllegalArgumentException(
                        "Expected " + URI_FRAGMENT_NEW_FILE_BASE + " key in intent bundle. Not found.");
            }
            afterResult = false;
            hasLaunched = false;
        }
    }

    @Override
    public String getAppName() {
        return appName;
    }

    @Override
    protected void onResume() {
        super.onResume();

        if (afterResult) {
            // this occurs if we re-orient the phone during the save-recording
            // action
            returnResult();
        } else if (!hasLaunched && !afterResult) {
            Intent i = null;
            if (launchIntent == null) {
                i = new Intent(android.provider.MediaStore.ACTION_IMAGE_CAPTURE);
            } else {
                i = launchIntent;
            }
            // workaround for image capture bug
            // create an empty file and pass filename to Camera app.
            if (uriFragmentToMedia == null) {
                uriFragmentToMedia = uriFragmentNewFileBase + TMP_EXTENSION;
            }
            // to make the name unique...
            File mediaFile = ODKFileUtils.getRowpathFile(appName, tableId, instanceId, uriFragmentToMedia);
            if (!mediaFile.exists()) {
                boolean success = false;
                String errorString = " Could not create: " + mediaFile.getAbsolutePath();
                try {
                    success = (mediaFile.getParentFile().exists() || mediaFile.getParentFile().mkdirs())
                            && mediaFile.createNewFile();
                } catch (IOException e) {
                    WebLogger.getLogger(appName).printStackTrace(e);
                    errorString = e.toString();
                } finally {
                    if (!success) {
                        String err = getString(R.string.media_save_failed);
                        WebLogger.getLogger(appName).e(t, err + errorString);
                        deleteMedia();
                        Toast.makeText(this, err, Toast.LENGTH_SHORT).show();
                        setResult(Activity.RESULT_CANCELED);
                        finish();
                        return;
                    }
                }
            }
            i.putExtra(android.provider.MediaStore.EXTRA_OUTPUT, Uri.fromFile(mediaFile));

            try {
                hasLaunched = true;
                startActivityForResult(i, ACTION_CODE);
            } catch (ActivityNotFoundException e) {
                String intentActivityName = null;
                if (launchIntent != null && launchIntent.getComponent() != null) {
                    intentActivityName = launchIntent.getComponent().getClassName();
                }
                String err = getString(R.string.activity_not_found,
                        android.provider.MediaStore.ACTION_IMAGE_CAPTURE);
                WebLogger.getLogger(appName).e(t, err);
                deleteMedia();
                Toast.makeText(this, err, Toast.LENGTH_SHORT).show();
                setResult(Activity.RESULT_CANCELED);
                finish();
            }
        }
    }

    @Override
    protected void onSaveInstanceState(Bundle outState) {
        super.onSaveInstanceState(outState);
        outState.putString(IntentConsts.INTENT_KEY_APP_NAME, appName);
        outState.putString(IntentConsts.INTENT_KEY_TABLE_ID, tableId);
        outState.putString(IntentConsts.INTENT_KEY_INSTANCE_ID, instanceId);
        outState.putString(IntentConsts.INTENT_KEY_URI_FRAGMENT, uriFragmentToMedia);
        outState.putString(IntentConsts.INTENT_KEY_CURRENT_URI_FRAGMENT, currentUriFragment);
        outState.putString(URI_FRAGMENT_NEW_FILE_BASE, uriFragmentNewFileBase);
        outState.putBoolean(HAS_LAUNCHED, hasLaunched);
        outState.putBoolean(AFTER_RESULT, afterResult);
    }

    protected void deleteMedia() {
        if (uriFragmentToMedia == null) {
            return;
        }
        // get the file path and delete the file
        File f = ODKFileUtils.getRowpathFile(appName, tableId, instanceId, uriFragmentToMedia);
        String path = f.getAbsolutePath();
        // delete from media provider
        int del = MediaUtils.deleteImageFileFromMediaProvider(this, appName, path);
        WebLogger.getLogger(appName).i(t, "Deleted " + del + " rows from image media content provider");
    }

    @Override
    public void onActivityResult(int requestCode, int resultCode, Intent intent) {

        if (resultCode == Activity.RESULT_CANCELED) {
            // request was canceled -- propagate
            setResult(Activity.RESULT_CANCELED);
            finish();
            return;
        }

        if (uriFragmentToMedia == null) {
            // we are in trouble
            WebLogger.getLogger(appName).e(t, "Unexpectedly null uriFragmentToMedia!");
            setResult(Activity.RESULT_CANCELED);
            finish();
            return;
        }

        if (uriFragmentNewFileBase == null) {
            // we are in trouble
            WebLogger.getLogger(appName).e(t, "Unexpectedly null newFileBase!");
            setResult(Activity.RESULT_CANCELED);
            finish();
            return;
        }

        File f = ODKFileUtils.getRowpathFile(appName, tableId, instanceId, uriFragmentToMedia);
        Uri mediaUri = Uri.fromFile(f);
        // we never have to deal with deleting, as the Camera is overwriting
        // this...

        // get the file path and create a copy in the instance folder
        String binaryPath = MediaUtils.getPathFromUri(this, (Uri) mediaUri, Images.Media.DATA);
        String extension = binaryPath.substring(binaryPath.lastIndexOf("."));

        File source = new File(binaryPath);
        File sourceMedia = ODKFileUtils.getRowpathFile(appName, tableId, instanceId,
                uriFragmentNewFileBase + extension);
        try {
            FileUtils.copyFile(source, sourceMedia);
        } catch (IOException e) {
            WebLogger.getLogger(appName).e(t, ERROR_COPY_FILE + sourceMedia.getAbsolutePath());
            Toast.makeText(this, R.string.media_save_failed, Toast.LENGTH_SHORT).show();
            setResult(Activity.RESULT_CANCELED);
            finish();
            return;
        }

        if (sourceMedia.exists()) {
            // Add the copy to the content provier
            ContentValues values = new ContentValues(6);
            values.put(Audio.Media.TITLE, sourceMedia.getName());
            values.put(Audio.Media.DISPLAY_NAME, sourceMedia.getName());
            values.put(Audio.Media.DATE_ADDED, System.currentTimeMillis());
            values.put(Audio.Media.DATA, sourceMedia.getAbsolutePath());

            Uri MediaURI = getApplicationContext().getContentResolver().insert(Images.Media.EXTERNAL_CONTENT_URI,
                    values);
            WebLogger.getLogger(appName).i(t, "Inserting IMAGE returned uri = " + MediaURI.toString());

            if (uriFragmentToMedia != null) {
                deleteMedia();
            }
            uriFragmentToMedia = ODKFileUtils.asRowpathUri(appName, tableId, instanceId, sourceMedia);
            WebLogger.getLogger(appName).i(t, "Setting current answer to " + sourceMedia.getAbsolutePath());
        } else {
            if (uriFragmentToMedia != null) {
                deleteMedia();
            }
            uriFragmentToMedia = null;
            WebLogger.getLogger(appName).e(t, "Inserting Image file FAILED");
        }

        /*
         * We saved the image to the instance directory. Verify that it is there...
         */
        returnResult();
        return;
    }

    protected void returnResult() {
        File sourceMedia = (uriFragmentToMedia != null)
                ? ODKFileUtils.getRowpathFile(appName, tableId, instanceId, uriFragmentToMedia)
                : null;
        if (sourceMedia != null && sourceMedia.exists()) {
            Intent i = new Intent();
            i.putExtra(IntentConsts.INTENT_KEY_URI_FRAGMENT,
                    ODKFileUtils.asRowpathUri(appName, tableId, instanceId, sourceMedia));
            String name = sourceMedia.getName();
            i.putExtra(IntentConsts.INTENT_KEY_CONTENT_TYPE,
                    MEDIA_CLASS + name.substring(name.lastIndexOf(".") + 1));
            setResult(Activity.RESULT_OK, i);
            finish();
        } else {
            WebLogger.getLogger(appName).e(t, ERROR_NO_FILE
                    + ((uriFragmentToMedia != null) ? sourceMedia.getAbsolutePath() : "null mediaPath"));
            Toast.makeText(this, R.string.media_save_failed, Toast.LENGTH_SHORT).show();
            setResult(Activity.RESULT_CANCELED);
            finish();
        }
    }

    @Override
    public void finish() {
        hasLaunched = false;
        afterResult = true;
        super.finish();
    }

    @Override
    public void databaseAvailable() {
    }

    @Override
    public void databaseUnavailable() {
    }

}