package com.u17od.upm; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.util.ArrayList; import java.util.Date; import java.util.List; import android.app.Activity; import android.app.ListActivity; import android.app.ProgressDialog; import android.content.Intent; import android.os.AsyncTask; import android.os.Bundle; import android.util.Log; import android.view.View; import android.widget.ArrayAdapter; import android.widget.ListView; import com.dropbox.client2.DropboxAPI; import com.dropbox.client2.android.AndroidAuthSession; import com.dropbox.client2.exception.DropboxException; import com.dropbox.client2.exception.DropboxUnlinkedException; import com.dropbox.client2.session.AccessTokenPair; import com.dropbox.client2.session.AppKeyPair; import com.u17od.upm.database.PasswordDatabase; public class SelectDatabaseFromDropboxActivity extends ListActivity { public static final String EXTRA_DB_FILENAMES = "EXTRA_DB_FILENAMES"; private static final int ENTER_PW_REQUEST_CODE = 111; private DropboxAPI<AndroidAuthSession> mDBApi; private ProgressDialog progressDialog; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.dropbox_file_list); // Prepare Dropbox Session objects AppKeyPair appKeys = new AppKeyPair(DropboxConstants.APP_KEY, DropboxConstants.APP_SECRET); AndroidAuthSession session = new AndroidAuthSession(appKeys, DropboxConstants.ACCESS_TYPE); mDBApi = new DropboxAPI<AndroidAuthSession>(session); AccessTokenPair accessTokenPair = Utilities.getDropboxAccessTokenPair(this); if (accessTokenPair != null) { mDBApi.getSession().setAccessTokenPair(accessTokenPair); } } @Override protected void onResume() { super.onResume(); // If we're returning from a successful Dropbox authentication then // update the session and store the access token pair if (mDBApi != null && mDBApi.getSession().authenticationSuccessful()) { // MANDATORY call to complete auth. // Sets the access token on the session mDBApi.getSession().finishAuthentication(); // store the tokens so we don't need to authenticate again // during this session AccessTokenPair tokens = mDBApi.getSession().getAccessTokenPair(); Utilities.setDropboxAccessTokenPair(this, tokens); } // Launch the async task where we'll download database filenames from // Dropbox and populate the ListView new DownloadListOfFilesTask().execute(); } @Override protected void onStop() { super.onStop(); if (progressDialog != null && progressDialog.isShowing()) { progressDialog.dismiss(); } } /** * The only way this method can be called is if we're returning from * EnterMasterPassword after retrieving a database. */ @Override protected void onActivityResult(int requestCode, int resultCode, Intent intent) { if (resultCode == Activity.RESULT_CANCELED) { UIUtilities.showToast(this, R.string.enter_password_cancalled); } else { if (requestCode == ENTER_PW_REQUEST_CODE) { // Setting the DatabaseFileName preference effectively says // that this is the db to open when the app starts Utilities.setSyncMethod(Prefs.SyncMethod.DROPBOX, this); String selectedDropboxFilename = Utilities.getConfig(this, Utilities.DROPBOX_PREFS, Utilities.DROPBOX_SELECTED_FILENAME); Utilities.setDatabaseFileName(selectedDropboxFilename, SelectDatabaseFromDropboxActivity.this); // Put a reference to the decrypted database on the Application object UPMApplication app = (UPMApplication) getApplication(); app.setPasswordDatabase(EnterMasterPassword.decryptedPasswordDatabase); app.setTimeOfLastSync(new Date()); setResult(RESULT_OK); finish(); } } } /** * Called when an file from the listview is selected */ @Override protected void onListItemClick(ListView lv, View v, int position, long id) { String selectedFileName = (String) lv.getItemAtPosition(position); Utilities.setConfig(this, Utilities.DROPBOX_PREFS, Utilities.DROPBOX_SELECTED_FILENAME, selectedFileName); new DownloadFileTask().execute(selectedFileName); } private class DownloadListOfFilesTask extends AsyncTask<Void, Void, Integer> { private static final int ERROR_CODE_DB_UNLINKED = 1; private static final int ERROR_CODE_DB_EXCEPTION = 2; private List<DropboxAPI.Entry> dropBoxEntries; protected void onPreExecute() { progressDialog = ProgressDialog.show(SelectDatabaseFromDropboxActivity.this, "", getString(R.string.dropbox_get_file_list)); } @Override protected Integer doInBackground(Void... params) { try { DropboxAPI.Entry rootMetadata = mDBApi.metadata("/", 100, null, true, null); dropBoxEntries = rootMetadata.contents; return 0; } catch (DropboxUnlinkedException e) { Log.e("DropboxDownloadActivity", "Dropbox Unlinked Exception", e); Utilities.clearDropboxAccessTokenPair(SelectDatabaseFromDropboxActivity.this); return ERROR_CODE_DB_UNLINKED; } catch (DropboxException e) { Log.e("AppEntryActivity", "Problem communicating with Dropbox", e); return ERROR_CODE_DB_EXCEPTION; } } @Override protected void onPostExecute(Integer result) { progressDialog.dismiss(); switch (result) { case 0: setListAdapter(new ArrayAdapter<String>( SelectDatabaseFromDropboxActivity.this, android.R.layout.simple_list_item_1, dropboxFiles(dropBoxEntries))); break; case ERROR_CODE_DB_UNLINKED: mDBApi.getSession().startAuthentication(SelectDatabaseFromDropboxActivity.this); break; case ERROR_CODE_DB_EXCEPTION: UIUtilities.showToast(SelectDatabaseFromDropboxActivity.this, R.string.dropbox_problem, true); break; } } /* * Extract the filenames from the given list of Dropbox Entries and return * a simple String array. */ private List<String> dropboxFiles(List<DropboxAPI.Entry> dpEntries) { List<String> fileNames = new ArrayList<String>(); for (DropboxAPI.Entry entry : dpEntries) { if (!entry.isDir) { fileNames.add(entry.fileName()); } } return fileNames; } } private class DownloadFileTask extends AsyncTask<String, Void, Integer> { private static final int ERROR_IO_ERROR = 1; private static final int ERROR_DROPBOX_ERROR = 2; private static final int NOT_UPM_DB = 3; protected void onPreExecute() { progressDialog = ProgressDialog.show(SelectDatabaseFromDropboxActivity.this, "", getString(R.string.downloading_db)); } @Override protected Integer doInBackground(String... fileName) { FileOutputStream outputStream = null; try { // Download the file and save it to UPM's internal files area File file = new File(getFilesDir(), fileName[0]); outputStream = new FileOutputStream(file); mDBApi.getFile(fileName[0], null, outputStream, null); // Check this is a UPM database file if (!PasswordDatabase.isPasswordDatabase(file)) { return NOT_UPM_DB; } EnterMasterPassword.databaseFileToDecrypt = file; return 0; } catch (DropboxException e) { return ERROR_DROPBOX_ERROR; } catch (IOException e) { return ERROR_IO_ERROR; } finally { if (outputStream != null) { try { outputStream.close(); } catch (IOException e) { return ERROR_IO_ERROR; } } } } @Override protected void onPostExecute(Integer result) { progressDialog.dismiss(); Intent i = null; switch (result) { case 0: // Call up the EnterMasterPassword activity // When it returns we'll pick up in the method onActivityResult i = new Intent(SelectDatabaseFromDropboxActivity.this, EnterMasterPassword.class); startActivityForResult(i, ENTER_PW_REQUEST_CODE); break; case ERROR_IO_ERROR: UIUtilities.showToast(SelectDatabaseFromDropboxActivity.this, R.string.problem_saving_db, true); break; case ERROR_DROPBOX_ERROR: UIUtilities.showToast(SelectDatabaseFromDropboxActivity.this, R.string.dropbox_problem, true); break; case NOT_UPM_DB: UIUtilities.showToast(SelectDatabaseFromDropboxActivity.this, R.string.not_password_database, true); break; } } } }