package org.commcare.activities;
import android.app.AlertDialog;
import android.content.DialogInterface;
import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;
import android.widget.Toast;
import org.commcare.CommCareApplication;
import org.commcare.dalvik.R;
import org.commcare.android.database.global.models.ApplicationRecord;
import org.commcare.google.services.analytics.GoogleAnalyticsFields;
import org.commcare.google.services.analytics.GoogleAnalyticsUtils;
import org.commcare.services.CommCareSessionService;
import org.commcare.tasks.UpdateTask;
import org.commcare.utils.LifecycleUtils;
import org.commcare.utils.MultipleAppsUtil;
import org.commcare.utils.SessionUnavailableException;
import org.commcare.views.dialogs.StandardAlertDialog;
/**
* The activity launched when the user clicks on a specific app within the app manager. From
* this screen, the selected app can be archived/unarchived, uninstalled, updated, or have its
* multimedia verified if needed.
*
* @author amstone
*/
public class SingleAppManagerActivity extends CommCareActivity {
private ApplicationRecord appRecord;
private static final int LOGOUT_FOR_UPDATE = 0;
private static final int LOGOUT_FOR_VERIFY_MM = 1;
private static final int LOGOUT_FOR_ARCHIVE = 2;
private static final int UPGRADE_APP = 0;
private static final int MISSING_MEDIA_ACTIVITY = 1;
private static final int SEAT_APP_ACTIVITY = 2;
private static final String KEY_LAUNCH_UPDATE_AFTER_SEATING = "launch-update-after-seating";
private boolean launchUpdateAfterSeating;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.single_app_view);
if (savedInstanceState != null) {
launchUpdateAfterSeating = savedInstanceState.getBoolean(KEY_LAUNCH_UPDATE_AFTER_SEATING);
}
// Retrieve the app record that should be represented by this activity
int position = getIntent().getIntExtra("position", -1);
appRecord = getAppForPosition(position);
if (appRecord == null) {
// Implies that this appRecord has been uninstalled since last we launched
// SingleAppManagerActivity, so redirect to AppManagerActivity
Intent i = new Intent(getApplicationContext(), AppManagerActivity.class);
startActivity(i);
finish();
}
//Set app name
String appName = appRecord.getDisplayName();
TextView tv = (TextView)findViewById(R.id.app_name);
tv.setText(appName);
}
@Override
protected void onResume() {
super.onResume();
refresh();
}
@Override
protected void onSaveInstanceState(Bundle outState) {
outState.putBoolean(KEY_LAUNCH_UPDATE_AFTER_SEATING, launchUpdateAfterSeating);
}
/**
* @param position the position in AppManagerActivity's list view that was clicked to trigger
* this activity
* @return the ApplicationRecord corresponding to the app that should be displayed in this
* activity, based upon the position
*/
private static ApplicationRecord getAppForPosition(int position) {
ApplicationRecord[] currentApps = MultipleAppsUtil.appRecordArray();
if (position < 0 || position >= currentApps.length) {
return null;
} else {
return currentApps[position];
}
}
/**
* Refresh all button appearances based on the current state of the app
*/
private void refresh() {
// Warns the user that this app came from an old version of the profile file, if necessary
TextView warning = (TextView)findViewById(R.id.profile_warning);
if (appRecord.isPreMultipleAppsProfile()) {
warning.setVisibility(View.VISIBLE);
} else {
warning.setVisibility(View.GONE);
}
// Updates text of the validate button based on the current state of the app's resources
Button validateButton = (Button)findViewById(R.id.verify_button);
if (appRecord.resourcesValidated()) {
validateButton.setVisibility(View.INVISIBLE);
} else {
validateButton.setVisibility(View.VISIBLE);
}
// Updates text of the archive button based on app's archive status
boolean isArchived = appRecord.isArchived();
Button archiveButton = (Button)findViewById(R.id.archive_button);
if (isArchived) {
archiveButton.setText(R.string.unarchive_app);
} else {
archiveButton.setText(R.string.archive_app);
}
// Sets the app version
int appVersion = appRecord.getVersionNumber();
TextView tv = (TextView)findViewById(R.id.app_version);
tv.setText("App Version: " + appVersion);
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent intent) {
switch (requestCode) {
case UPGRADE_APP:
if (resultCode == RESULT_CANCELED) {
UpdateTask task = UpdateTask.getRunningInstance();
if (task != null) {
Toast.makeText(this, R.string.update_canceled, Toast.LENGTH_LONG).show();
task.cancel(true);
}
} else if (resultCode == RESULT_OK) {
// update activity may have writen to the app record storage, so get new changes
appRecord = MultipleAppsUtil.getAppById(appRecord.getUniqueId());
refresh();
}
return;
case MISSING_MEDIA_ACTIVITY:
refresh();
if (resultCode == RESULT_CANCELED) {
String title = getString(R.string.media_not_verified);
String msg = getString(R.string.skipped_verification_warning_2);
showAlertDialog(StandardAlertDialog.getBasicAlertDialog(this, title, msg, null));
} else if (resultCode == RESULT_OK) {
Toast.makeText(this, R.string.media_verified, Toast.LENGTH_LONG).show();
}
return;
case SEAT_APP_ACTIVITY:
if (resultCode == RESULT_OK) {
if (launchUpdateAfterSeating) {
launchUpdateActivity();
} else {
launchVerificationActivity();
}
}
return;
}
super.onActivityResult(requestCode, resultCode, intent);
}
/**
* Uninstalls the selected app
*/
private void uninstall() {
GoogleAnalyticsUtils.reportAppManagerAction(GoogleAnalyticsFields.ACTION_UNINSTALL_APP);
CommCareApplication.instance().expireUserSession();
CommCareApplication.instance().uninstall(appRecord);
LifecycleUtils.restartCommCare(
SingleAppManagerActivity.this, AppManagerActivity.class, false);
}
/**
* onClick method for Archive button. If the app is not archived, sets it to archived
* (i.e. still installed but not visible to users). If it is archived, sets it to unarchived
*
* @param v linter sees this as unused, but is required for a button to find its onClick method
*/
public void toggleArchiveClicked(View v) {
if (CommCareApplication.instance().isSeated(appRecord)) {
try {
CommCareSessionService s = CommCareApplication.instance().getSession();
if (s.isActive()) {
triggerLogoutWarning(LOGOUT_FOR_ARCHIVE);
} else {
toggleArchived();
}
} catch (SessionUnavailableException e) {
toggleArchived();
}
} else {
toggleArchived();
}
}
private void toggleArchived() {
if (!appRecord.isArchived()) {
GoogleAnalyticsUtils.reportAppManagerAction(GoogleAnalyticsFields.ACTION_ARCHIVE_APP);
}
appRecord.setArchiveStatus(!appRecord.isArchived());
CommCareApplication.instance().getGlobalStorage(ApplicationRecord.class).write(appRecord);
if (CommCareApplication.instance().isSeated(appRecord)) {
CommCareApplication.instance().getCurrentApp().refreshAppRecord();
}
refresh();
}
/**
* onClick method for Validate Multimedia button
*
* @param v linter sees this as unused, but is required for a button to find its onClick method
*/
public void verifyResourcesClicked(View v) {
try {
CommCareSessionService s = CommCareApplication.instance().getSession();
if (s.isActive()) {
triggerLogoutWarning(LOGOUT_FOR_VERIFY_MM);
} else {
verifyResources();
}
} catch (SessionUnavailableException e) {
verifyResources();
}
}
/**
* Opens the MM verification activity for the selected app
*/
private void verifyResources() {
if (!CommCareApplication.instance().isSeated(appRecord)) {
launchUpdateAfterSeating = false;
seatApp();
} else {
launchVerificationActivity();
}
}
private void launchVerificationActivity() {
Intent i = new Intent(this, CommCareVerificationActivity.class);
i.putExtra(AppManagerActivity.KEY_LAUNCH_FROM_MANAGER, true);
this.startActivityForResult(i, MISSING_MEDIA_ACTIVITY);
}
/**
* onClick method for Update button
*
* @param v linter sees this as unused, but is required for a button to find its onClick method
*/
public void updateClicked(View v) {
try {
CommCareSessionService s = CommCareApplication.instance().getSession();
if (s.isActive()) {
triggerLogoutWarning(LOGOUT_FOR_UPDATE);
} else {
update();
}
} catch (SessionUnavailableException e) {
update();
}
}
/**
* Conducts an update for the selected app
*/
private void update() {
if (!CommCareApplication.instance().isSeated(appRecord)) {
launchUpdateAfterSeating = true;
seatApp();
} else {
launchUpdateActivity();
}
}
private void seatApp() {
Intent i = new Intent(this, SeatAppActivity.class);
i.putExtra(SeatAppActivity.KEY_APP_TO_SEAT, appRecord.getUniqueId());
this.startActivityForResult(i, SEAT_APP_ACTIVITY);
}
private void launchUpdateActivity() {
Intent i = new Intent(getApplicationContext(), UpdateActivity.class);
i.putExtra(AppManagerActivity.KEY_LAUNCH_FROM_MANAGER, true);
startActivityForResult(i, UPGRADE_APP);
}
/**
* onClick method for Uninstall button. Before actually conducting the uninstall, warns
* the user that it will also result in a reboot of CC
*
* @param v linter sees this as unused, but is required for a button to find its onClick method
*/
public void rebootAlertDialog(View v) {
StandardAlertDialog d = new StandardAlertDialog(this, getString(R.string.uninstalling),
getString(R.string.uninstall_reboot_warning));
DialogInterface.OnClickListener listener = new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
dismissAlertDialog();
if (which == AlertDialog.BUTTON_POSITIVE) {
uninstall();
}
}
};
d.setPositiveButton(getString(R.string.ok), listener);
d.setNegativeButton(getString(R.string.cancel), listener);
showAlertDialog(d);
}
/**
* Warns a user that the action they are trying to conduct will result in the current
* session being logged out
*/
private void triggerLogoutWarning(final int actionKey) {
StandardAlertDialog d = new StandardAlertDialog(this, getString(R.string.logging_out),
getString(R.string.logout_warning));
DialogInterface.OnClickListener listener = new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog,
int which) {
dismissAlertDialog();
if (which == AlertDialog.BUTTON_POSITIVE) {
CommCareApplication.instance().expireUserSession();
switch (actionKey) {
case LOGOUT_FOR_UPDATE:
update();
break;
case LOGOUT_FOR_VERIFY_MM:
verifyResources();
break;
case LOGOUT_FOR_ARCHIVE:
toggleArchived();
}
}
}
};
d.setPositiveButton(getString(R.string.ok), listener);
d.setNegativeButton(getString(R.string.cancel), listener);
showAlertDialog(d);
}
@Override
protected boolean shouldShowBreadcrumbBar() {
return false;
}
}