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.BackupDataImporter; import com.code44.finance.data.backup.DataImporter; import com.code44.finance.data.backup.DataImporterRunnable; import com.code44.finance.data.backup.DriveDataImporterRunnable; import com.code44.finance.data.db.DBHelper; 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.ImportError; 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.FileInputStream; import java.io.FileNotFoundException; import java.io.InputStream; import java.util.concurrent.Executor; import javax.inject.Inject; public class ImportActivity extends BaseActivity { private static final String EXTRA_IMPORT_TYPE = "EXTRA_IMPORT_TYPE"; private static final String EXTRA_SOURCE = "EXTRA_SOURCE"; private static final int REQUEST_LOCAL_FILE = 1; private static final int REQUEST_DRIVE_FILE = 2; private static final String FRAGMENT_GOOGLE_API = "FRAGMENT_GOOGLE_API"; private static final String UNIQUE_GOOGLE_API_ID = ImportActivity.class.getName(); private static final String STATE_IS_PROCESS_STARTED = "STATE_IS_PROCESS_STARTED"; private static final String STATE_IS_FILE_REQUESTED = "STATE_IS_FILE_REQUESTED"; @Inject GoogleApiConnection connection; @Inject @Local Executor localExecutor; @Inject GeneralPrefs generalPrefs; @Inject DBHelper dbHelper; private ImportType importType; private Source source; private GoogleApiClient googleApiClient; private boolean isProcessStarted = false; private boolean isFileRequested = false; public static void start(Context context, ImportType importType, Source source) { final Intent intent = makeIntentForActivity(context, ImportActivity.class); intent.putExtra(EXTRA_IMPORT_TYPE, importType); intent.putExtra(EXTRA_SOURCE, source); startActivity(context, intent); } @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_import); // Get extras importType = (ImportType) getIntent().getSerializableExtra(EXTRA_IMPORT_TYPE); source = (Source) getIntent().getSerializableExtra(EXTRA_SOURCE); // Restore state if (savedInstanceState != null) { isProcessStarted = savedInstanceState.getBoolean(STATE_IS_PROCESS_STARTED, false); isFileRequested = savedInstanceState.getBoolean(STATE_IS_FILE_REQUESTED, false); } } @Override protected void onResume() { super.onResume(); getEventBus().register(this); if (!isProcessStarted) { isProcessStarted = true; isFileRequested = source.startImportProcess(this, generalPrefs); } } @Override protected void onSaveInstanceState(Bundle outState) { super.onSaveInstanceState(outState); outState.putBoolean(STATE_IS_PROCESS_STARTED, isProcessStarted); outState.putBoolean(STATE_IS_FILE_REQUESTED, isFileRequested); } @Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { if (resultCode != RESULT_OK) { finish(); return; } switch (requestCode) { case REQUEST_LOCAL_FILE: final String path = data.getData().getPath(); onLocalFileSelected(new File(path)); break; case REQUEST_DRIVE_FILE: final DriveId driveId = data.getParcelableExtra(OpenFileActivityBuilder.EXTRA_RESPONSE_DRIVE_ID); googleApiClient = connection.get(UNIQUE_GOOGLE_API_ID); onDriveFileSelected(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 ImportError) { finish(); } } @Override protected Analytics.Screen getScreen() { return Analytics.Screen.Import; } @Subscribe public void onDataImporterFinished(DataImporter dataImporter) { Toast.makeText(this, R.string.done, Toast.LENGTH_SHORT).show(); finish(); } @Subscribe public void onGoogleApiClientConnected(GoogleApiConnection connection) { if (isFileRequested || !connection.contains(UNIQUE_GOOGLE_API_ID)) { return; } googleApiClient = connection.get(UNIQUE_GOOGLE_API_ID); final IntentSender intentSender = Drive.DriveApi .newOpenFileActivityBuilder() .setMimeType(new String[]{"application/json"}) .build(googleApiClient); try { startIntentSenderForResult(intentSender, REQUEST_DRIVE_FILE, null, 0, 0, 0); isFileRequested = true; } catch (IntentSender.SendIntentException e) { throw new ImportError("Unable to show Google Drive.", e); } } private void onDriveFileSelected(DriveId driveId) { importData(new DriveDataImporterRunnable(googleApiClient, driveId, importType, this, dbHelper, getEventBus())); } private void onLocalFileSelected(File file) { final InputStream inputStream; try { inputStream = new FileInputStream(file); } catch (FileNotFoundException e) { throw new ImportError("Data import failed.", e); } final DataImporter dataImporter = importType.getDataImporter(inputStream, this, dbHelper); importData(new DataImporterRunnable(getEventBus(), dataImporter)); } private void importData(Runnable importRunnable) { localExecutor.execute(importRunnable); } public static enum ImportType { Backup { @Override public DataImporter getDataImporter(InputStream inputStream, Context context, DBHelper dbHelper) { return new BackupDataImporter(inputStream, context, dbHelper, false); } }, MergeBackup { @Override public DataImporter getDataImporter(InputStream inputStream, Context context, DBHelper dbHelper) { return new BackupDataImporter(inputStream, context, dbHelper, true); } }, CSV { @Override public DataImporter getDataImporter(InputStream inputStream, Context context, DBHelper dbHelper) { throw new IllegalStateException("CSV import is not supported."); } }; public abstract DataImporter getDataImporter(InputStream inputStream, Context context, DBHelper dbHelper); } public static enum Source { File { @Override public boolean startImportProcess(BaseActivity activity, GeneralPrefs generalPrefs) { FilePickerActivity.startFile(activity, REQUEST_LOCAL_FILE, generalPrefs.getLastFileExportPath()); return true; } }, GoogleDrive { @Override public boolean startImportProcess(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 startImportProcess(BaseActivity activity, GeneralPrefs generalPrefs); } }