package org.commcare.activities;
import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.os.Environment;
import android.util.Log;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.TextView;
import android.widget.Toast;
import org.commcare.CommCareApplication;
import org.commcare.dalvik.R;
import org.commcare.resources.model.MissingMediaException;
import org.commcare.tasks.VerificationTask;
import org.commcare.utils.ConsumerAppsUtil;
import org.commcare.utils.MultipleAppsUtil;
import org.commcare.views.dialogs.CustomProgressDialog;
import org.javarosa.core.services.locale.Localization;
import org.javarosa.core.util.SizeBoundVector;
import java.util.Enumeration;
import java.util.Hashtable;
import java.util.Vector;
/**
* Performs media validation and allows for the installation of missing media
*/
public class CommCareVerificationActivity
extends CommCareActivity<CommCareVerificationActivity>
implements OnClickListener {
private static final String TAG = CommCareVerificationActivity.class.getSimpleName();
private TextView missingMediaPrompt;
private static final int MENU_UNZIP = Menu.FIRST;
private static final String KEY_REQUIRE_REFRESH = "require_referesh";
public static final String KEY_LAUNCH_FROM_SETTINGS = "from_settings";
private static final int DIALOG_VERIFY_PROGRESS = 0;
private static final String MISSING_MEDIA_TEXT_KEY = "missing-media-text-key";
private static final String NEW_MEDIA_KEY = "new-media-to-validate";
/**
* Return code for launching media inflater (selector).
*/
private static final int GET_MULTIMEDIA = 0;
/**
* When new media is installed, set this so that verification is fired
* onPostResume.
*/
private boolean newMediaToValidate = false;
/**
* Indicates whether this activity was launched from the AppManagerActivity
*/
private boolean fromManager;
/**
* Indicates whether this activity was launched explicitly from the settings menu in
* CommCareHomeActivity
*/
private boolean fromSettings;
private boolean isFirstLaunch;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (CommCareApplication.instance().isConsumerApp()) {
setContentView(R.layout.blank_missing_multimedia_layout);
} else {
setContentView(R.layout.missing_multimedia_layout);
}
Button retryButton = (Button)findViewById(R.id.screen_multimedia_retry);
retryButton.setOnClickListener(this);
retryButton.setText(Localization.get("verify.retry"));
this.fromSettings = this.getIntent().
getBooleanExtra(KEY_LAUNCH_FROM_SETTINGS, false);
this.fromManager = this.getIntent().
getBooleanExtra(AppManagerActivity.KEY_LAUNCH_FROM_MANAGER, false);
if (fromManager) {
Button skipButton = (Button)findViewById(R.id.skip_verification_button);
skipButton.setVisibility(View.VISIBLE);
skipButton.setOnClickListener(this);
}
missingMediaPrompt = (TextView)findViewById(R.id.MissingMediaPrompt);
loadStateFromBundle(savedInstanceState);
isFirstLaunch = (savedInstanceState == null);
}
private void loadStateFromBundle(Bundle savedInstanceState) {
if (savedInstanceState != null) {
if (savedInstanceState.containsKey(MISSING_MEDIA_TEXT_KEY)) {
missingMediaPrompt.setText(savedInstanceState.getString(MISSING_MEDIA_TEXT_KEY));
} else {
missingMediaPrompt.setText(Localization.get("verify.checking"));
}
if (savedInstanceState.containsKey(NEW_MEDIA_KEY)) {
newMediaToValidate = savedInstanceState.getBoolean(NEW_MEDIA_KEY);
}
}
}
@Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
outState.putString(MISSING_MEDIA_TEXT_KEY, missingMediaPrompt.getText().toString());
outState.putBoolean(NEW_MEDIA_KEY, newMediaToValidate);
}
@Override
protected void onResume() {
super.onResume();
// It is possible that the CommCare screen was left off in the VerificationActivity, but
// then something was done on the Manager screen that means we no longer want to be here --
// VerificationActivity should be displayed to a user only if we were explicitly sent from
// the manager, or if the state of installed apps calls for it
boolean shouldBeHere = fromManager || fromSettings || MultipleAppsUtil.shouldSeeMMVerification();
if (!shouldBeHere) {
// send back to dispatch activity
setResult(RESULT_OK);
finish();
}
}
@Override
protected void onPostResume() {
super.onPostResume();
if (isFirstLaunch) {
isFirstLaunch = false;
verifyResourceInstall();
} else if (newMediaToValidate) {
newMediaToValidate = false;
verifyResourceInstall();
}
}
private void verifyResourceInstall() {
// there shouldn't be another verification task running, but just in case
cancelCurrentTask();
VerificationTask<CommCareVerificationActivity> task =
new VerificationTask<CommCareVerificationActivity>(DIALOG_VERIFY_PROGRESS) {
@Override
protected void deliverResult(CommCareVerificationActivity receiver,
SizeBoundVector<MissingMediaException> problems) {
if (problems == null) {
receiver.handleVerificationSuccess();
} else {
if (problems.size() == 0) {
receiver.handleVerificationSuccess();
} else if (problems.size() > 0) {
receiver.handleVerificationProblems(problems);
}
}
}
@Override
protected void deliverUpdate(CommCareVerificationActivity receiver,
int[]... update) {
final int done = update[0][0];
final int pending = update[0][1];
receiver.updateProgress(
Localization.get("verification.progress", new String[]{"" + done, "" + pending}),
DIALOG_VERIFY_PROGRESS);
updateProgressBar(done, pending, DIALOG_VERIFY_PROGRESS);
}
@Override
protected void deliverError(CommCareVerificationActivity receiver,
Exception e) {
receiver.missingMediaPrompt.setText(Localization.get("exception.during.verification", e.getMessage()));
}
};
task.connect(this);
task.executeParallel();
}
@Override
public void taskCancelled() {
}
private void handleVerificationProblems(SizeBoundVector<MissingMediaException> problems) {
String message = Localization.get("verification.fail.message");
Hashtable<String, Vector<String>> problemList = new Hashtable<>();
for (Enumeration en = problems.elements(); en.hasMoreElements(); ) {
MissingMediaException ure = (MissingMediaException)en.nextElement();
String res = ure.getResource().getResourceId();
Vector<String> list;
if (problemList.containsKey(res)) {
list = problemList.get(res);
} else {
list = new Vector<>();
}
list.addElement(ure.getMessage());
problemList.put(res, list);
}
for (Enumeration en = problemList.keys(); en.hasMoreElements(); ) {
String resource = (String)en.nextElement();
message += "\n-----------";
for (String s : problemList.get(resource)) {
message += "\n" + prettyString(s);
}
}
if (problems.getAdditional() > 0) {
message += "\n\n..." + problems.getAdditional() + " more";
}
missingMediaPrompt.setText(message);
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent intent) {
if (requestCode == GET_MULTIMEDIA && resultCode == Activity.RESULT_OK) {
// we found some media, so try validating it
newMediaToValidate = true;
return;
}
super.onActivityResult(requestCode, resultCode, intent);
}
private void handleVerificationSuccess() {
CommCareApplication.instance().getCurrentApp().setMMResourcesValidated();
if (Intent.ACTION_VIEW.equals(CommCareVerificationActivity.this.getIntent().getAction())) {
//Call out to CommCare Home
Intent i = new Intent(getApplicationContext(), DispatchActivity.class);
i.putExtra(KEY_REQUIRE_REFRESH, true);
startActivity(i);
} else {
//Good to go
Intent i = new Intent(getIntent());
i.putExtra(KEY_REQUIRE_REFRESH, true);
setResult(RESULT_OK, i);
}
if (!CommCareApplication.instance().isConsumerApp()) {
Toast.makeText(getApplicationContext(), Localization.get("verification.success.message"), Toast.LENGTH_SHORT).show();
}
finish();
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
super.onCreateOptionsMenu(menu);
menu.add(0, MENU_UNZIP, 0, "Install Multimedia").setIcon(android.R.drawable.ic_menu_gallery);
return true;
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case MENU_UNZIP:
Intent i = new Intent(this, MultimediaInflaterActivity.class);
i.putExtra(MultimediaInflaterActivity.EXTRA_FILE_DESTINATION,
CommCareApplication.instance().getCurrentApp().storageRoot());
this.startActivityForResult(i, GET_MULTIMEDIA);
return true;
}
return super.onOptionsItemSelected(item);
}
@Override
public CustomProgressDialog generateProgressDialog(int taskId) {
if (CommCareApplication.instance().isConsumerApp()) {
return ConsumerAppsUtil.getGenericConsumerAppsProgressDialog(taskId, false);
}
if (taskId == DIALOG_VERIFY_PROGRESS) {
CustomProgressDialog dialog =
CustomProgressDialog.newInstance(
Localization.get("verification.title"),
Localization.get("verification.checking"),
taskId);
dialog.addProgressBar();
if (fromSettings || fromManager) {
dialog.addCancelButton();
}
return dialog;
}
Log.w(TAG, "taskId passed to generateProgressDialog does not match "
+ "any valid possibilities in CommCareVerificationActivity");
return null;
}
@Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.skip_verification_button:
Intent i = new Intent(getIntent());
setResult(RESULT_CANCELED, i);
finish();
break;
case R.id.screen_multimedia_retry:
verifyResourceInstall();
break;
}
}
private String prettyString(String rawString) {
int marker = rawString.indexOf(Environment.getExternalStorageDirectory().getPath());
if (marker < 0) {
return rawString;
} else {
return rawString.substring(marker);
}
}
}