package cgeo.geocaching;
import cgeo.geocaching.activity.AbstractActionBarActivity;
import cgeo.geocaching.models.Image;
import cgeo.geocaching.settings.Settings;
import cgeo.geocaching.ui.dialog.Dialogs;
import cgeo.geocaching.utils.ImageUtils;
import cgeo.geocaching.utils.Log;
import android.content.Intent;
import android.database.Cursor;
import android.graphics.Bitmap;
import android.net.Uri;
import android.os.AsyncTask;
import android.os.Build;
import android.os.Build.VERSION_CODES;
import android.os.Bundle;
import android.provider.MediaStore;
import android.provider.MediaStore.MediaColumns;
import android.support.annotation.Nullable;
import android.view.View;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemSelectedListener;
import android.widget.Button;
import android.widget.EditText;
import android.widget.ImageView;
import android.widget.Spinner;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import butterknife.BindView;
import butterknife.ButterKnife;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.StringUtils;
public class ImageSelectActivity extends AbstractActionBarActivity {
@BindView(R.id.caption) protected EditText captionView;
@BindView(R.id.description) protected EditText descriptionView;
@BindView(R.id.logImageScale) protected Spinner scaleView;
@BindView(R.id.camera) protected Button cameraButton;
@BindView(R.id.stored) protected Button storedButton;
@BindView(R.id.save) protected Button saveButton;
@BindView(R.id.cancel) protected Button clearButton;
@BindView(R.id.image_preview) protected ImageView imagePreview;
private static final String SAVED_STATE_IMAGE = "cgeo.geocaching.saved_state_image";
private static final String SAVED_STATE_IMAGE_SCALE = "cgeo.geocaching.saved_state_image_scale";
private static final int SELECT_NEW_IMAGE = 1;
private static final int SELECT_STORED_IMAGE = 2;
// Data to be saved while reconfiguring
private Image image;
private int scaleChoiceIndex;
@Override
public void onCreate(final Bundle savedInstanceState) {
onCreate(savedInstanceState, R.layout.imageselect_activity);
ButterKnife.bind(this);
scaleChoiceIndex = Settings.getLogImageScale();
// Get parameters from intent and basic cache information from database
final Bundle extras = getIntent().getExtras();
if (extras != null) {
image = extras.getParcelable(Intents.EXTRA_IMAGE);
scaleChoiceIndex = extras.getInt(Intents.EXTRA_SCALE, scaleChoiceIndex);
final String geocode = extras.getString(Intents.EXTRA_GEOCODE);
setCacheTitleBar(geocode);
}
// Restore previous state
if (savedInstanceState != null) {
image = savedInstanceState.getParcelable(SAVED_STATE_IMAGE);
scaleChoiceIndex = savedInstanceState.getInt(SAVED_STATE_IMAGE_SCALE);
}
if (image == null) {
image = Image.NONE;
}
cameraButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(final View view) {
selectImageFromCamera();
}
});
storedButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(final View view) {
selectImageFromStorage();
}
});
if (image.hasTitle()) {
captionView.setText(image.getTitle());
Dialogs.moveCursorToEnd(captionView);
}
if (image.hasDescription()) {
descriptionView.setText(image.getDescription());
Dialogs.moveCursorToEnd(captionView);
}
scaleView.setSelection(scaleChoiceIndex);
scaleView.setOnItemSelectedListener(new OnItemSelectedListener() {
@Override
public void onItemSelected(final AdapterView<?> arg0, final View arg1, final int arg2, final long arg3) {
scaleChoiceIndex = scaleView.getSelectedItemPosition();
Settings.setLogImageScale(scaleChoiceIndex);
}
@Override
public void onNothingSelected(final AdapterView<?> arg0) {
}
});
saveButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(final View v) {
saveImageInfo(true);
}
});
clearButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(final View v) {
saveImageInfo(false);
}
});
loadImagePreview();
}
@Override
protected void onSaveInstanceState(final Bundle outState) {
super.onSaveInstanceState(outState);
syncEditTexts();
outState.putParcelable(SAVED_STATE_IMAGE, image);
outState.putInt(SAVED_STATE_IMAGE_SCALE, scaleChoiceIndex);
}
public void saveImageInfo(final boolean saveInfo) {
if (saveInfo) {
new AsyncTask<Void, Void, String>() {
@Override
protected String doInBackground(final Void... params) {
return writeScaledImage(image.getPath());
}
@Override
protected void onPostExecute(final String filename) {
if (filename != null) {
image = new Image.Builder().setUrl(filename).build();
final Intent intent = new Intent();
syncEditTexts();
intent.putExtra(Intents.EXTRA_IMAGE, image);
intent.putExtra(Intents.EXTRA_SCALE, scaleChoiceIndex);
setResult(RESULT_OK, intent);
} else {
showToast(res.getString(R.string.err_select_logimage_failed));
setResult(RESULT_CANCELED);
}
finish();
}
}.execute();
} else {
setResult(RESULT_CANCELED);
finish();
}
}
private void syncEditTexts() {
image = new Image.Builder()
.setUrl(image.uri)
.setTitle(captionView.getText().toString())
.setDescription(descriptionView.getText().toString())
.build();
scaleChoiceIndex = scaleView.getSelectedItemPosition();
}
private void selectImageFromCamera() {
final Uri imageUri = ImageUtils.getOutputImageFileUri();
if (imageUri == null) {
showFailure();
return;
}
image = new Image.Builder().setUrl(imageUri).build();
if (image.isEmpty()) {
showFailure();
return;
}
// create Intent to take a picture and return control to the calling application
final Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
intent.putExtra(MediaStore.EXTRA_OUTPUT, image.getUri()); // set the image file name
// start the image capture Intent
startActivityForResult(intent, SELECT_NEW_IMAGE);
}
private void selectImageFromStorage() {
final Intent intent = new Intent(Intent.ACTION_GET_CONTENT);
intent.setType("image/jpeg");
startActivityForResult(Intent.createChooser(intent, "Select Image"), SELECT_STORED_IMAGE);
}
@Override
protected void onActivityResult(final int requestCode, final int resultCode, final Intent data) {
if (resultCode == RESULT_CANCELED) {
// User cancelled the image capture
showToast(getString(R.string.info_select_logimage_cancelled));
return;
}
if (resultCode != RESULT_OK) {
// Image capture failed, advise user
showFailure();
return;
}
// null is an acceptable result if the image has been placed in the imageUri file by the
// camera application.
if (data != null) {
final Uri selectedImage = data.getData();
// In principal can selectedImage be null
if (selectedImage != null) {
if (Build.VERSION.SDK_INT < VERSION_CODES.KITKAT) {
final String[] filePathColumn = { MediaColumns.DATA };
Cursor cursor = null;
try {
cursor = getContentResolver().query(selectedImage, filePathColumn, null, null, null);
if (cursor == null) {
showFailure();
return;
}
cursor.moveToFirst();
final int columnIndex = cursor.getColumnIndex(filePathColumn[0]);
final String filePath = cursor.getString(columnIndex);
if (StringUtils.isBlank(filePath)) {
showFailure();
return;
}
image = new Image.Builder().setUrl(filePath).build();
} catch (final Exception e) {
Log.e("ImageSelectActivity.onActivityResult", e);
showFailure();
} finally {
if (cursor != null) {
cursor.close(); // no Closable Cursor below sdk 16
}
}
Log.d("SELECT IMAGE data = " + data.toString());
} else {
InputStream input = null;
OutputStream output = null;
try {
input = getContentResolver().openInputStream(selectedImage);
final File outputFile = ImageUtils.getOutputImageFile();
if (outputFile != null) {
output = new FileOutputStream(outputFile);
IOUtils.copy(input, output);
image = new Image.Builder().setUrl(outputFile).build();
}
} catch (final IOException e) {
Log.e("ImageSelectActivity.onActivityResult", e);
} finally {
IOUtils.closeQuietly(input);
IOUtils.closeQuietly(output);
}
}
} else {
// Image capture failed, advise user
showFailure();
return;
}
}
if (requestCode == SELECT_NEW_IMAGE) {
showToast(getString(R.string.info_stored_image) + '\n' + image.getUrl());
}
loadImagePreview();
}
/**
* Scales and writes the scaled image.
*
* @return the scaled image path, or <tt>null</tt> if the image cannot be decoded
*/
@Nullable
private String writeScaledImage(@Nullable final String filePath) {
if (filePath == null) {
return null;
}
scaleChoiceIndex = scaleView.getSelectedItemPosition();
final int maxXY = getResources().getIntArray(R.array.log_image_scale_values)[scaleChoiceIndex];
return ImageUtils.readScaleAndWriteImage(filePath, maxXY);
}
private void showFailure() {
showToast(getString(R.string.err_acquire_image_failed));
}
private void loadImagePreview() {
if (image.isEmpty()) {
return;
}
if (!image.existsLocal()) {
Log.i("Image does not exist");
return;
}
new AsyncTask<Void, Void, Bitmap>() {
@Override
protected Bitmap doInBackground(final Void... params) {
return ImageUtils.readAndScaleImageToFitDisplay(image.getPath());
}
@Override
protected void onPostExecute(final Bitmap bitmap) {
imagePreview.setImageBitmap(bitmap);
imagePreview.setVisibility(View.VISIBLE);
}
}.execute();
}
}