org.odk.collect.android.widgets.DrawWidget.java Source code

Java tutorial

Introduction

Here is the source code for org.odk.collect.android.widgets.DrawWidget.java

Source

/*
 * Copyright (C) 2007 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 org.odk.collect.android.widgets;

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

import org.javarosa.core.model.data.IAnswerData;
import org.javarosa.core.model.data.StringData;
import org.javarosa.form.api.FormEntryPrompt;
import org.odk.collect.android.activities.DrawActivity;
import org.odk.collect.android.utilities.FileUtils;

import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.database.Cursor;
import android.graphics.Bitmap;
import android.net.Uri;
import android.provider.MediaStore.Images;
import android.util.Log;
import android.util.TypedValue;
import android.view.Display;
import android.view.View;
import android.view.WindowManager;
import android.view.inputmethod.InputMethodManager;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TableLayout;
import android.widget.TextView;

import com.radicaldynamic.groupinform.activities.FormEntryActivity;
import com.radicaldynamic.groupinform.application.Collect;
import com.radicaldynamic.groupinform.utilities.FileUtilsExtended;

public class DrawWidget extends QuestionWidget implements IBinaryWidget {
    private static final String t = "DrawWidget: ";

    private Button mCaptureButton;
    private FormEntryPrompt mPrompt;
    private ImageView mImageView;
    private TextView mErrorTextView;

    private String mBinaryName;
    private String mDrawMode;
    private String mInstanceFolder;
    private boolean mWaitingForData = false;

    public DrawWidget(Context context, FormEntryPrompt prompt) {
        super(context, prompt);
        mPrompt = prompt;

        setupScreen();
    }

    // Alternate constructor used if "appearance" attribute is set on <upload ... />
    public DrawWidget(Context context, FormEntryPrompt prompt, String drawMode) {
        super(context, prompt);
        mPrompt = prompt;
        mDrawMode = drawMode;

        setupScreen();
    }

    @Override
    public void clearAnswer() {
        // remove the file
        deleteMedia();
        mImageView.setImageBitmap(null);
        mErrorTextView.setVisibility(View.GONE);

        // reset buttons
        mCaptureButton.setText(getCapturePrompt());
    }

    @Override
    public IAnswerData getAnswer() {
        if (mBinaryName != null) {
            return new StringData(mBinaryName.toString());
        } else {
            return null;
        }
    }

    @Override
    public void setFocus(Context context) {
        // Hide the soft keyboard if it's showing.
        InputMethodManager inputManager = (InputMethodManager) context
                .getSystemService(Context.INPUT_METHOD_SERVICE);
        inputManager.hideSoftInputFromWindow(this.getWindowToken(), 0);
    }

    @Override
    public void setOnLongClickListener(OnLongClickListener l) {
        // Not enabled here
    }

    @Override
    public boolean isWaitingForBinaryData() {
        return mWaitingForData;
    }

    @Override
    public void setBinaryData(Object answer) {
        // Delete the previous image using the content provider
        if (mBinaryName != null) {
            deleteMedia();
        }

        mBinaryName = (new File(getPathFromUri((Uri) answer))).getName();
        Log.i(t, "Setting current answer to " + mBinaryName);

        mWaitingForData = false;
    }

    // Taken from ImageWidget
    private void deleteMedia() {
        // Get the file path and delete the file

        /*
         * There's only 1 in this case, but android 1.6 doesn't implement delete on
         * android.provider.MediaStore.Images.Media.EXTERNAL_CONTENT_URI only on
         * android.provider.MediaStore.Images.Media.EXTERNAL_CONTENT_URI + a #
         */
        String[] projection = { Images.ImageColumns._ID };

        Cursor c = getContext().getContentResolver().query(
                android.provider.MediaStore.Images.Media.EXTERNAL_CONTENT_URI, projection,
                "_data='" + mInstanceFolder + mBinaryName + "'", null, null);

        int del = 0;

        if (c.getCount() > 0) {
            c.moveToFirst();
            String id = c.getString(c.getColumnIndex(Images.ImageColumns._ID));

            Log.i(t, "attempting to delete: "
                    + Uri.withAppendedPath(android.provider.MediaStore.Images.Media.EXTERNAL_CONTENT_URI, id));
            del = getContext().getContentResolver().delete(
                    Uri.withAppendedPath(android.provider.MediaStore.Images.Media.EXTERNAL_CONTENT_URI, id), null,
                    null);
        }

        c.close();

        // Clean up variables
        mBinaryName = null;

        Log.i(t, "Deleted " + del + " rows from media content provider");
    }

    private String getCapturePrompt() {
        String capturePrompt = "";

        if (mDrawMode == null || mDrawMode.contains("sketch")) {
            capturePrompt = "Open Sketchpad";
        } else if (mDrawMode.contains("signature")) {
            capturePrompt = mBinaryName == null ? "Capture Signature" : "Edit Signature";
        } else if (mDrawMode.contains("annotate")) {
            capturePrompt = mBinaryName == null ? "Annotate Image" : "Edit Annotation";
        }

        return capturePrompt;
    }

    private String getPathFromUri(Uri uri) {
        if (uri.toString().startsWith("file")) {
            return uri.toString().substring(6);
        } else {
            // Find entry in content provider
            Cursor c = getContext().getContentResolver().query(uri, null, null, null, null);
            c.moveToFirst();

            // Get data path
            String colString = c.getString(c.getColumnIndex("_data"));
            c.close();

            return colString;
        }
    }

    private void setupScreen() {
        setOrientation(LinearLayout.VERTICAL);

        // Retrieve answer from data model and update ui
        mBinaryName = mPrompt.getAnswerText();

        // Set location of folder containing answer
        mInstanceFolder = FormEntryActivity.mInstancePath.substring(0,
                FormEntryActivity.mInstancePath.lastIndexOf("/") + 1);

        // Error text, if needed
        mErrorTextView = new TextView(getContext());
        mErrorTextView.setText("Selected file is not a valid image");

        LayoutParams layoutParams = new TableLayout.LayoutParams();
        layoutParams.setMargins(7, 5, 7, 5);

        mCaptureButton = new Button(getContext());
        mCaptureButton.setText(getCapturePrompt());
        mCaptureButton.setTextSize(TypedValue.COMPLEX_UNIT_DIP, mAnswerFontsize);
        mCaptureButton.setPadding(20, 20, 20, 20);
        mCaptureButton.setEnabled(!mPrompt.isReadOnly());
        mCaptureButton.setLayoutParams(layoutParams);

        // Launch capture intent on click
        mCaptureButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                mWaitingForData = true;
                mErrorTextView.setVisibility(View.GONE);

                File tmp = new File(
                        FileUtilsExtended.EXTERNAL_CACHE + File.separator + FileUtilsExtended.CAPTURED_IMAGE_FILE);

                // Copy existing image into temporary slot (edit existing image)
                if (mBinaryName == null) {
                    // Remove this file if it's still sitting around
                    tmp.delete();
                } else {
                    try {
                        org.apache.commons.io.FileUtils.copyFile(new File(mInstanceFolder, mBinaryName), tmp);
                    } catch (IOException e) {
                        Log.e(Collect.LOGTAG,
                                t + "unable to copy existing binary image to temporary location: " + e.toString());
                        e.printStackTrace();
                    }
                }

                Intent i = new Intent(getContext(), DrawActivity.class);
                i.putExtra(DrawActivity.KEY_DRAW_MODE, mDrawMode);
                i.putExtra(DrawActivity.KEY_OUTPUT_URI, Uri.fromFile(tmp));
                ((Activity) getContext()).startActivityForResult(i, FormEntryActivity.IMAGE_CAPTURE);
            }
        });

        addView(mCaptureButton);

        // Proceed to add the imageView only if the user has taken a picture
        if (mBinaryName == null)
            return;

        // Below taken from ImageWidget (w/o onClick for loading a larger image)
        mImageView = new ImageView(getContext());

        Display display = ((WindowManager) getContext().getSystemService(Context.WINDOW_SERVICE))
                .getDefaultDisplay();
        int screenWidth = display.getWidth();
        int screenHeight = display.getHeight();

        File f = new File(mInstanceFolder + "/" + mBinaryName);

        if (f.exists()) {
            Bitmap bmp = FileUtils.getBitmapScaledToDisplay(f, screenHeight, screenWidth);

            if (bmp == null) {
                mErrorTextView.setVisibility(View.VISIBLE);
            }

            mImageView.setImageBitmap(bmp);
        } else {
            mImageView.setImageBitmap(null);
        }

        mImageView.setPadding(10, 10, 10, 10);
        mImageView.setAdjustViewBounds(true);

        addView(mImageView);
    }
}