/*
* Copyright (C) 2009 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.odk.collect.android.widgets;
import android.app.Activity;
import android.content.ActivityNotFoundException;
import android.content.ContentValues;
import android.content.Context;
import android.content.Intent;
import android.net.Uri;
import android.provider.MediaStore.Audio;
import android.util.Log;
import android.util.TypedValue;
import android.view.View;
import android.view.inputmethod.InputMethodManager;
import android.widget.Button;
import android.widget.LinearLayout;
import android.widget.TableLayout;
import android.widget.Toast;
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.R;
import org.odk.collect.android.activities.FormEntryActivity;
import org.odk.collect.android.application.Collect;
import org.odk.collect.android.utilities.FileUtils;
import org.odk.collect.android.utilities.MediaUtils;
import java.io.File;
/**
* Widget that allows user to take pictures, sounds or video and add them to the
* form.
*
* @author Carl Hartung (carlhartung@gmail.com)
* @author Yaw Anokwa (yanokwa@gmail.com)
*/
public class AudioWidget extends QuestionWidget implements IBinaryWidget {
private final static String t = "MediaWidget";
private Button mCaptureButton;
private Button mPlayButton;
private Button mChooseButton;
private String mBinaryName;
private String mInstanceFolder;
public AudioWidget(Context context, FormEntryPrompt prompt) {
super(context, prompt);
mInstanceFolder = Collect.getInstance().getFormController()
.getInstancePath().getParent();
setOrientation(LinearLayout.VERTICAL);
TableLayout.LayoutParams params = new TableLayout.LayoutParams();
params.setMargins(7, 5, 7, 5);
// setup capture button
mCaptureButton = new Button(getContext());
mCaptureButton.setId(QuestionWidget.newUniqueId());
mCaptureButton.setText(getContext().getString(R.string.capture_audio));
mCaptureButton
.setTextSize(TypedValue.COMPLEX_UNIT_DIP, mAnswerFontsize);
mCaptureButton.setPadding(20, 20, 20, 20);
mCaptureButton.setEnabled(!prompt.isReadOnly());
mCaptureButton.setLayoutParams(params);
// launch capture intent on click
mCaptureButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Collect.getInstance()
.getActivityLogger()
.logInstanceAction(this, "captureButton", "click",
mPrompt.getIndex());
Intent i = new Intent(
android.provider.MediaStore.Audio.Media.RECORD_SOUND_ACTION);
i.putExtra(
android.provider.MediaStore.EXTRA_OUTPUT,
android.provider.MediaStore.Audio.Media.EXTERNAL_CONTENT_URI
.toString());
try {
Collect.getInstance().getFormController()
.setIndexWaitingForData(mPrompt.getIndex());
((Activity) getContext()).startActivityForResult(i,
FormEntryActivity.AUDIO_CAPTURE);
} catch (ActivityNotFoundException e) {
Toast.makeText(
getContext(),
getContext().getString(R.string.activity_not_found,
"audio capture"), Toast.LENGTH_SHORT)
.show();
Collect.getInstance().getFormController()
.setIndexWaitingForData(null);
}
}
});
// setup capture button
mChooseButton = new Button(getContext());
mChooseButton.setId(QuestionWidget.newUniqueId());
mChooseButton.setText(getContext().getString(R.string.choose_sound));
mChooseButton.setTextSize(TypedValue.COMPLEX_UNIT_DIP, mAnswerFontsize);
mChooseButton.setPadding(20, 20, 20, 20);
mChooseButton.setEnabled(!prompt.isReadOnly());
mChooseButton.setLayoutParams(params);
// launch capture intent on click
mChooseButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Collect.getInstance()
.getActivityLogger()
.logInstanceAction(this, "chooseButton", "click",
mPrompt.getIndex());
Intent i = new Intent(Intent.ACTION_GET_CONTENT);
i.setType("audio/*");
try {
Collect.getInstance().getFormController()
.setIndexWaitingForData(mPrompt.getIndex());
((Activity) getContext()).startActivityForResult(i,
FormEntryActivity.AUDIO_CHOOSER);
} catch (ActivityNotFoundException e) {
Toast.makeText(
getContext(),
getContext().getString(R.string.activity_not_found,
"choose audio"), Toast.LENGTH_SHORT).show();
Collect.getInstance().getFormController()
.setIndexWaitingForData(null);
}
}
});
// setup play button
mPlayButton = new Button(getContext());
mPlayButton.setId(QuestionWidget.newUniqueId());
mPlayButton.setText(getContext().getString(R.string.play_audio));
mPlayButton.setTextSize(TypedValue.COMPLEX_UNIT_DIP, mAnswerFontsize);
mPlayButton.setPadding(20, 20, 20, 20);
mPlayButton.setLayoutParams(params);
// on play, launch the appropriate viewer
mPlayButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Collect.getInstance()
.getActivityLogger()
.logInstanceAction(this, "playButton", "click",
mPrompt.getIndex());
Intent i = new Intent("android.intent.action.VIEW");
File f = new File(mInstanceFolder + File.separator
+ mBinaryName);
i.setDataAndType(Uri.fromFile(f), "audio/*");
try {
((Activity) getContext()).startActivity(i);
} catch (ActivityNotFoundException e) {
Toast.makeText(
getContext(),
getContext().getString(R.string.activity_not_found,
"play audio"), Toast.LENGTH_SHORT).show();
}
}
});
// retrieve answer from data model and update ui
mBinaryName = prompt.getAnswerText();
if (mBinaryName != null) {
mPlayButton.setEnabled(true);
} else {
mPlayButton.setEnabled(false);
}
// finish complex layout
addView(mCaptureButton);
addView(mChooseButton);
addView(mPlayButton);
// and hide the capture and choose button if read-only
if (mPrompt.isReadOnly()) {
mCaptureButton.setVisibility(View.GONE);
mChooseButton.setVisibility(View.GONE);
}
}
private void deleteMedia() {
// get the file path and delete the file
String name = mBinaryName;
// clean up variables
mBinaryName = null;
// delete from media provider
int del = MediaUtils.deleteAudioFileFromMediaProvider(mInstanceFolder + File.separator + name);
Log.i(t, "Deleted " + del + " rows from media content provider");
}
@Override
public void clearAnswer() {
// remove the file
deleteMedia();
// reset buttons
mPlayButton.setEnabled(false);
}
@Override
public IAnswerData getAnswer() {
if (mBinaryName != null) {
return new StringData(mBinaryName.toString());
} else {
return null;
}
}
@Override
public void setBinaryData(Object binaryuri) {
// when replacing an answer. remove the current media.
if (mBinaryName != null) {
deleteMedia();
}
// get the file path and create a copy in the instance folder
String binaryPath = MediaUtils.getPathFromUri(this.getContext(), (Uri) binaryuri, Audio.Media.DATA);
String extension = binaryPath.substring(binaryPath.lastIndexOf("."));
String destAudioPath = mInstanceFolder + File.separator
+ System.currentTimeMillis() + extension;
File source = new File(binaryPath);
File newAudio = new File(destAudioPath);
FileUtils.copyFile(source, newAudio);
if (newAudio.exists()) {
// Add the copy to the content provier
ContentValues values = new ContentValues(6);
values.put(Audio.Media.TITLE, newAudio.getName());
values.put(Audio.Media.DISPLAY_NAME, newAudio.getName());
values.put(Audio.Media.DATE_ADDED, System.currentTimeMillis());
values.put(Audio.Media.DATA, newAudio.getAbsolutePath());
Uri AudioURI = getContext().getContentResolver().insert(
Audio.Media.EXTERNAL_CONTENT_URI, values);
Log.i(t, "Inserting AUDIO returned uri = " + AudioURI.toString());
mBinaryName = newAudio.getName();
Log.i(t, "Setting current answer to " + newAudio.getName());
} else {
Log.e(t, "Inserting Audio file FAILED");
}
Collect.getInstance().getFormController().setIndexWaitingForData(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 boolean isWaitingForBinaryData() {
return mPrompt.getIndex().equals(
Collect.getInstance().getFormController()
.getIndexWaitingForData());
}
@Override
public void cancelWaitingForBinaryData() {
Collect.getInstance().getFormController().setIndexWaitingForData(null);
}
@Override
public void setOnLongClickListener(OnLongClickListener l) {
mCaptureButton.setOnLongClickListener(l);
mChooseButton.setOnLongClickListener(l);
mPlayButton.setOnLongClickListener(l);
}
@Override
public void cancelLongPress() {
super.cancelLongPress();
mCaptureButton.cancelLongPress();
mChooseButton.cancelLongPress();
mPlayButton.cancelLongPress();
}
}