package com.code44.finance.ui.settings.data; import android.content.Context; import android.content.Intent; import android.content.IntentSender; import android.os.Bundle; import android.widget.Toast; import com.code44.finance.R; import com.code44.finance.data.backup.BackupDataExporter; import com.code44.finance.data.backup.CsvDataExporter; import com.code44.finance.data.backup.DataExporter; import com.code44.finance.data.backup.DataExporterRunnable; import com.code44.finance.data.backup.DriveDataExporterRunnable; import com.code44.finance.qualifiers.Local; import com.code44.finance.ui.FilePickerActivity; import com.code44.finance.ui.common.BaseActivity; import com.code44.finance.ui.playservices.GoogleApiConnection; import com.code44.finance.ui.playservices.GoogleApiFragment; import com.code44.finance.utils.GeneralPrefs; import com.code44.finance.utils.analytics.Analytics; import com.code44.finance.utils.errors.AppError; import com.code44.finance.utils.errors.ExportError; import com.google.android.gms.common.api.GoogleApiClient; import com.google.android.gms.drive.Drive; import com.google.android.gms.drive.DriveId; import com.google.android.gms.drive.OpenFileActivityBuilder; import com.squareup.otto.Subscribe; import java.io.File; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.OutputStream; import java.text.SimpleDateFormat; import java.util.Date; import java.util.concurrent.Executor; import javax.inject.Inject; public class ExportActivity extends BaseActivity { private static final String EXTRA_EXPORT_TYPE = "EXTRA_EXPORT_TYPE"; private static final String EXTRA_DESTINATION = "EXTRA_DESTINATION"; private static final int REQUEST_LOCAL_DIRECTORY = 1; private static final int REQUEST_DRIVE_DIRECTORY = 2; private static final String FRAGMENT_GOOGLE_API = "FRAGMENT_GOOGLE_API"; private static final String UNIQUE_GOOGLE_API_ID = ExportActivity.class.getName(); private static final String STATE_IS_PROCESS_STARTED = "STATE_IS_PROCESS_STARTED"; private static final String STATE_IS_DIRECTORY_REQUESTED = "STATE_IS_DIRECTORY_REQUESTED"; @Inject GoogleApiConnection connection; @Inject @Local Executor localExecutor; @Inject GeneralPrefs generalPrefs; private ExportType exportType; private Destination destination; private GoogleApiClient googleApiClient; private boolean isProcessStarted = false; private boolean isDirectoryRequested = false; public static void start(Context context, ExportType exportType, Destination destination) { final Intent intent = makeIntentForActivity(context, ExportActivity.class); intent.putExtra(EXTRA_EXPORT_TYPE, exportType); intent.putExtra(EXTRA_DESTINATION, destination); startActivity(context, intent); } @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_export); // Get extras exportType = (ExportType) getIntent().getSerializableExtra(EXTRA_EXPORT_TYPE); destination = (Destination) getIntent().getSerializableExtra(EXTRA_DESTINATION); // Restore state if (savedInstanceState != null) { isProcessStarted = savedInstanceState.getBoolean(STATE_IS_PROCESS_STARTED, false); isDirectoryRequested = savedInstanceState.getBoolean(STATE_IS_DIRECTORY_REQUESTED, false); } } @Override protected void onResume() { super.onResume(); getEventBus().register(this); if (!isProcessStarted) { isProcessStarted = true; isDirectoryRequested = destination.startExportProcess(this, generalPrefs); } } @Override protected void onSaveInstanceState(Bundle outState) { super.onSaveInstanceState(outState); outState.putBoolean(STATE_IS_PROCESS_STARTED, isProcessStarted); outState.putBoolean(STATE_IS_DIRECTORY_REQUESTED, isDirectoryRequested); } @Override public void onActivityResult(int requestCode, int resultCode, Intent data) { if (resultCode != RESULT_OK) { finish(); return; } switch (requestCode) { case REQUEST_LOCAL_DIRECTORY: final String path = data.getData().getPath(); generalPrefs.setLastFileExportPath(path); onLocalDirectorySelected(new File(path)); break; case REQUEST_DRIVE_DIRECTORY: final DriveId driveId = data.getParcelableExtra(OpenFileActivityBuilder.EXTRA_RESPONSE_DRIVE_ID); // TODO Maybe store this driveId to open Google Drive in this folder next time. googleApiClient = connection.get(UNIQUE_GOOGLE_API_ID); onDriveDirectorySelected(driveId); break; } final GoogleApiFragment googleApi_F = (GoogleApiFragment) getSupportFragmentManager().findFragmentByTag(FRAGMENT_GOOGLE_API); if (googleApi_F != null) { googleApi_F.handleOnActivityResult(requestCode, resultCode); } super.onActivityResult(requestCode, resultCode, data); } @Override protected void onPause() { super.onPause(); getEventBus().unregister(this); } @Override protected void onHandleError(AppError error) { super.onHandleError(error); if (error instanceof ExportError) { finish(); } } @Override protected Analytics.Screen getScreen() { return Analytics.Screen.Export; } @Subscribe public void onDataExporterFinished(DataExporter dataExporter) { Toast.makeText(this, R.string.done, Toast.LENGTH_SHORT).show(); finish(); } @Subscribe public void onGoogleApiClientConnected(GoogleApiConnection connection) { if (isDirectoryRequested || !connection.contains(UNIQUE_GOOGLE_API_ID)) { return; } googleApiClient = connection.get(UNIQUE_GOOGLE_API_ID); final IntentSender intentSender = Drive.DriveApi .newOpenFileActivityBuilder() .setMimeType(new String[]{"application/vnd.google-apps.folder"}) .build(googleApiClient); try { startIntentSenderForResult(intentSender, REQUEST_DRIVE_DIRECTORY, null, 0, 0, 0); isDirectoryRequested = true; } catch (IntentSender.SendIntentException e) { throw new ExportError("Unable to show Google Drive.", e); } } private void onDriveDirectorySelected(DriveId driveId) { exportData(new DriveDataExporterRunnable(googleApiClient, driveId, exportType, destination, this, getEventBus(), getFileTitle())); } private void onLocalDirectorySelected(File directory) { final File file = getFile(directory); final OutputStream outputStream; try { outputStream = new FileOutputStream(file); } catch (FileNotFoundException e) { throw new ExportError("Data export has failed.", e); } final DataExporter dataExporter = exportType.getDataExporter(outputStream, this); exportData(new DataExporterRunnable(getEventBus(), dataExporter)); } private File getFile(File directory) { return new File(directory, getFileTitle()); } private String getFileTitle() { final SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HHmmss"); return getString(R.string.app_name) + " " + dateFormat.format(new Date()) + exportType.getExtension(); } private void exportData(Runnable exportRunnable) { localExecutor.execute(exportRunnable); } public static enum ExportType { Backup { @Override public DataExporter getDataExporter(OutputStream outputStream, Context context) { return new BackupDataExporter(outputStream, context); } @Override public String getExtension() { return ".json"; } @Override public String getMimeType(Destination destination) { return "application/json"; } }, CSV { @Override public DataExporter getDataExporter(OutputStream outputStream, Context context) { return new CsvDataExporter(outputStream, context); } @Override public String getExtension() { return ".csv"; } @Override public String getMimeType(Destination destination) { return "text/csv"; } }; public abstract DataExporter getDataExporter(OutputStream outputStream, Context context); public abstract String getExtension(); public abstract String getMimeType(Destination destination); } public static enum Destination { File { @Override public boolean startExportProcess(BaseActivity activity, GeneralPrefs generalPrefs) { FilePickerActivity.startDir(activity, REQUEST_LOCAL_DIRECTORY, generalPrefs.getLastFileExportPath()); return true; } }, GoogleDrive { @Override public boolean startExportProcess(BaseActivity activity, GeneralPrefs generalPrefs) { GoogleApiFragment googleApi_F = (GoogleApiFragment) activity.getSupportFragmentManager().findFragmentByTag(FRAGMENT_GOOGLE_API); if (googleApi_F == null) { googleApi_F = GoogleApiFragment.with(UNIQUE_GOOGLE_API_ID).setUseDrive(true).build(); activity.getSupportFragmentManager().beginTransaction().add(android.R.id.content, googleApi_F, FRAGMENT_GOOGLE_API).commit(); } googleApi_F.connect(); return false; } }; public abstract boolean startExportProcess(BaseActivity activity, GeneralPrefs generalPrefs); } }