package org.commcare.activities;
import android.app.Activity;
import android.content.ActivityNotFoundException;
import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
import android.os.Environment;
import android.util.Log;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.EditText;
import android.widget.ImageButton;
import android.widget.TextView;
import android.widget.Toast;
import org.commcare.CommCareApplication;
import org.commcare.dalvik.R;
import org.commcare.tasks.MultimediaInflaterTask;
import org.commcare.tasks.templates.CommCareTask;
import org.commcare.utils.FileUtil;
import org.commcare.utils.UriToFilePath;
import org.commcare.views.ManagedUi;
import org.commcare.views.UiElement;
import org.commcare.views.dialogs.CustomProgressDialog;
import org.javarosa.core.services.locale.Localization;
import java.io.File;
import java.util.ArrayList;
/**
* @author ctsims
*/
@ManagedUi(R.layout.screen_multimedia_inflater)
public class MultimediaInflaterActivity extends SessionAwareCommCareActivity<MultimediaInflaterActivity> {
private static final String TAG = MultimediaInflaterActivity.class.getSimpleName();
private static final String LOG_TAG = "CC-MultimediaInflator";
public static final int REQUEST_FILE_LOCATION = 1;
public static final String EXTRA_FILE_DESTINATION = "ccodk_mia_filedest";
@UiElement(value = R.id.screen_multimedia_inflater_prompt, locale = "mult.install.prompt")
TextView txtDisplayPrompt;
@UiElement(value = R.id.screen_multimedia_install_messages, locale = "mult.install.state.empty")
TextView txtInteractiveMessages;
@UiElement(R.id.screen_multimedia_inflater_location)
EditText editFileLocation;
@UiElement(R.id.screen_multimedia_inflater_filefetch)
ImageButton btnFetchFiles;
@UiElement(value = R.id.screen_multimedia_inflater_install, locale = "mult.install.button")
Button btnInstallMultimedia;
private boolean done = false;
@Override
protected void onCreate(Bundle savedInstanceState) {
final String destination = this.getIntent().getStringExtra(EXTRA_FILE_DESTINATION);
super.onCreate(savedInstanceState);
btnFetchFiles.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
//Go fetch us a file path!
Intent intent = new Intent(Intent.ACTION_GET_CONTENT);
// only allow look for zip files
intent.setType("application/zip");
try {
startActivityForResult(intent, REQUEST_FILE_LOCATION);
} catch (ActivityNotFoundException e) {
Toast.makeText(MultimediaInflaterActivity.this, Localization.get("mult.install.no.browser"), Toast.LENGTH_LONG).show();
}
}
});
btnInstallMultimedia.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
MultimediaInflaterTask<MultimediaInflaterActivity> task = new MultimediaInflaterTask<MultimediaInflaterActivity>() {
@Override
protected void deliverResult(MultimediaInflaterActivity receiver, Boolean result) {
if (result == Boolean.TRUE) {
receiver.done = true;
receiver.evalState();
receiver.setResult(Activity.RESULT_OK);
receiver.finish();
} else {
//assume that we've already set the error message, but make it look scary
receiver.transplantStyle(txtInteractiveMessages, R.layout.template_text_notification_problem);
}
}
@Override
protected void deliverUpdate(MultimediaInflaterActivity receiver, String... update) {
receiver.updateProgress(update[0], CommCareTask.GENERIC_TASK_ID);
receiver.txtInteractiveMessages.setText(update[0]);
}
@Override
protected void deliverError(MultimediaInflaterActivity receiver, Exception e) {
receiver.txtInteractiveMessages.setText(Localization.get("mult.install.error", new String[]{e.getMessage()}));
receiver.transplantStyle(txtInteractiveMessages, R.layout.template_text_notification_problem);
}
};
task.connect(MultimediaInflaterActivity.this);
task.executeParallel(editFileLocation.getText().toString(), destination);
}
});
try {
//Go populate the location by default if it exists. (Note: If we are recreating, this will get overridden
//in the restore instance state)
searchForDefault();
} catch (Exception e) {
//This is helper code and Android is suuuuuppppeerr touchy about file system stuff, so don't eat it if
//something changes
e.printStackTrace();
Log.e(LOG_TAG, "Error while trying to get default location");
}
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent intent) {
if (requestCode == REQUEST_FILE_LOCATION) {
if (resultCode == Activity.RESULT_OK) {
// Android versions 4.4 and up sometimes don't return absolute
// filepaths from the file chooser. So resolve the URI into a
// valid file path.
Uri uriPath = intent.getData();
if (uriPath == null) {
// issue getting the filepath uri from file browser callout
// result
Toast.makeText(this,
Localization.get("mult.install.state.invalid.path"),
Toast.LENGTH_SHORT).show();
} else {
String filePath =
UriToFilePath.getPathFromUri(CommCareApplication.instance(), uriPath);
if (filePath != null) {
editFileLocation.setText(filePath);
}
}
}
}
}
@Override
protected void onResumeSessionSafe() {
evalState();
}
private void evalState() {
if (done) {
txtInteractiveMessages.setText(Localization.get("mult.install.state.done"));
this.transplantStyle(txtInteractiveMessages, R.layout.template_text_notification);
btnInstallMultimedia.setEnabled(false);
return;
}
String location = editFileLocation.getText().toString();
if ("".equals(location)) {
txtInteractiveMessages.setText(Localization.get("mult.install.state.empty"));
this.transplantStyle(txtInteractiveMessages, R.layout.template_text_notification);
btnInstallMultimedia.setEnabled(false);
return;
}
if (!(new File(location)).exists()) {
txtInteractiveMessages.setText(Localization.get("mult.install.state.invalid.path"));
this.transplantStyle(txtInteractiveMessages, R.layout.template_text_notification_problem);
btnInstallMultimedia.setEnabled(false);
} else {
txtInteractiveMessages.setText(Localization.get("mult.install.state.ready"));
this.transplantStyle(txtInteractiveMessages, R.layout.template_text_notification);
btnInstallMultimedia.setEnabled(true);
}
}
@Override
public void taskCancelled() {
txtInteractiveMessages.setText(Localization.get("mult.install.cancelled"));
this.transplantStyle(txtInteractiveMessages, R.layout.template_text_notification_problem);
}
private static final long MAX_TIME_TO_TRY = 400;
/**
* Go through all of the obvious storage locations where the zip file might be and see if it's there.
*/
private void searchForDefault() {
//We're only gonna spend a certain amount of time trying to find a good match
long start = System.currentTimeMillis();
//Get all of the "roots" where stuff might be
ArrayList<File> roots = new ArrayList<>();
//And stage a place to list folders we'll scan
ArrayList<File> folders = new ArrayList<>();
if (Environment.MEDIA_MOUNTED.equals(Environment.getExternalStorageState()) ||
Environment.MEDIA_MOUNTED_READ_ONLY.equals(Environment.getExternalStorageState())) {
roots.add(Environment.getExternalStorageDirectory());
}
for (String s : FileUtil.getExternalMounts()) {
roots.add(new File(s));
}
//Now add all of our folders from our roots. We're only going one level deep
for (File r : roots) {
//Add the root too
folders.add(r);
//Now add all subfolders
for (File f : r.listFiles()) {
if (f.isDirectory()) {
folders.add(f);
}
}
}
File bestMatch = null;
//Now scan for the actual file
for (File folder : folders) {
for (File f : folder.listFiles()) {
String name = f.getName().toLowerCase();
//This is just what we expect the file will be called
if (name.startsWith("commcare") && name.endsWith(".zip")) {
if (bestMatch == null) {
bestMatch = f;
} else {
//If we have one, take the newer one
if (bestMatch.lastModified() < f.lastModified()) {
bestMatch = f;
}
}
}
}
//For now, actually, if we have a good match, just bail without finding the "best" one
if (bestMatch != null) {
break;
}
if (System.currentTimeMillis() - start > MAX_TIME_TO_TRY) {
Log.i(LOG_TAG, "Had to bail on looking for a default file, was taking too long");
break;
}
}
if (bestMatch != null) {
//If we found a good match, awesome!
editFileLocation.setText(bestMatch.getAbsolutePath());
}
}
/**
* Implementation of generateProgressDialog() for DialogController -- other methods
* handled entirely in CommCareActivity
*/
@Override
public CustomProgressDialog generateProgressDialog(int taskId) {
if (taskId == CommCareTask.GENERIC_TASK_ID) {
String title = Localization.get("mult.install.title");
String message = Localization.get("mult.install.progress", new String[]{"0"});
return CustomProgressDialog.newInstance(title, message, taskId);
}
Log.w(TAG, "taskId passed to generateProgressDialog does not match "
+ "any valid possibilities in MultiMediaInflaterActivity");
return null;
}
}