/* * 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); } }