diff --git a/res/values/strings.xml b/res/values/strings.xml
index 3d92f35..446e24e 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -113,10 +113,12 @@
1 Recipe Scaled
1 Recipe Copied
1 Recipe Exported
+ All Recipes Exported
Import Recipe(s) from XML
Select a BeerXML (.xml) or BeerSmith2 (.bsmx) file to import recipes.
- GDrive
+ GDrive
+ SD Card
diff --git a/src/com/biermacht/brews/frontend/IngredientActivities/AddEditActivity.java b/src/com/biermacht/brews/frontend/IngredientActivities/AddEditActivity.java
index 413fb35..a685305 100644
--- a/src/com/biermacht/brews/frontend/IngredientActivities/AddEditActivity.java
+++ b/src/com/biermacht/brews/frontend/IngredientActivities/AddEditActivity.java
@@ -1,6 +1,7 @@
package com.biermacht.brews.frontend.IngredientActivities;
import android.content.Context;
+import android.content.Intent;
import android.content.SharedPreferences;
import android.os.Bundle;
import android.support.v7.app.AlertDialog;
@@ -29,6 +30,7 @@
import com.biermacht.brews.utils.AlertBuilder;
import com.biermacht.brews.utils.Callbacks.Callback;
import com.biermacht.brews.utils.Constants;
+import com.biermacht.brews.utils.DriveActivity;
import com.biermacht.brews.utils.IngredientHandler;
import java.util.ArrayList;
@@ -40,7 +42,7 @@
* examples would be Recipes, MashProfiles, or Settings. This class defines a framework for adding
* views, acquiring values from those views, saving or deleting objects, and more.
*/
-public abstract class AddEditActivity extends AppCompatActivity implements OnClickListener {
+public abstract class AddEditActivity extends DriveActivity implements OnClickListener {
// Main view - holds all the rows
public ViewGroup mainView;
@@ -413,6 +415,16 @@ public void onClick(View v) {
}
}
+ @Override
+ public void onDriveFilePicked(Intent data) {
+ // Not used.
+ }
+
+ @Override
+ public void onDriveFileWritten(Intent data) {
+ // Not used.
+ }
+
public void registerViews(List views) {
if (this.registeredViews == null) {
Log.d("AddEditActivity", "Initializing registeredViews");
diff --git a/src/com/biermacht/brews/frontend/MainActivity.java b/src/com/biermacht/brews/frontend/MainActivity.java
index 7f8782c..9b09eae 100644
--- a/src/com/biermacht/brews/frontend/MainActivity.java
+++ b/src/com/biermacht/brews/frontend/MainActivity.java
@@ -5,7 +5,6 @@
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
-import android.content.IntentSender;
import android.content.SharedPreferences;
import android.content.res.Configuration;
import android.net.Uri;
@@ -17,7 +16,6 @@
import android.support.v4.widget.DrawerLayout;
import android.support.v7.app.ActionBarDrawerToggle;
import android.support.v7.app.AlertDialog;
-import android.support.v7.app.AppCompatActivity;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.MenuItem;
@@ -45,12 +43,10 @@
import com.biermacht.brews.tasks.ImportXmlIngredientsTask;
import com.biermacht.brews.tasks.InitializeTask;
import com.biermacht.brews.utils.Constants;
+import com.biermacht.brews.utils.DriveActivity;
import com.biermacht.brews.utils.IngredientHandler;
import com.biermacht.brews.utils.comparators.ToStringComparator;
import com.biermacht.brews.utils.interfaces.BiermachtFragment;
-import com.google.android.gms.common.ConnectionResult;
-import com.google.android.gms.common.GoogleApiAvailability;
-import com.google.android.gms.common.api.GoogleApiClient;
import com.google.android.gms.common.api.ResultCallback;
import com.google.android.gms.drive.Drive;
import com.google.android.gms.drive.DriveApi;
@@ -67,7 +63,7 @@
import java.util.Collections;
import java.util.Iterator;
-public class MainActivity extends AppCompatActivity implements GoogleApiClient.ConnectionCallbacks, GoogleApiClient.OnConnectionFailedListener {
+public class MainActivity extends DriveActivity {
// Globals, referenced outside of this Activity.
// TODO: These should not be use globally - can cause null reference when application is killed and re-started.
@@ -96,10 +92,6 @@ public class MainActivity extends AppCompatActivity implements GoogleApiClient.C
private ActionBarDrawerToggle mDrawerToggle;
private ListView drawerListView;
- // Google Play API client
- private GoogleApiClient mGoogleApiClient;
- private ProgressDialog progressDialog;
-
// Currently selected drawer item - for use as an index in drawerItems and fragmentList.
private int selectedItem;
@@ -121,17 +113,6 @@ public void onCreate(Bundle savedInstanceState) {
// Instantiate ingredient handler
ingredientHandler = new IngredientHandler(getApplicationContext());
- // Create the Google API client used for accessing Google Services such as Drive.
- mGoogleApiClient = new GoogleApiClient.Builder(this)
- .addApi(Drive.API)
- .addScope(Drive.SCOPE_FILE)
- .addConnectionCallbacks(this)
- .addOnConnectionFailedListener(this)
- .build();
-
- // Create the progress dialog view - displayed when connecting to Google APIs.
- progressDialog = new ProgressDialog(MainActivity.this);
-
// Get shared preferences
preferences = this.getSharedPreferences(Constants.PREFERENCES, Context.MODE_PRIVATE);
@@ -216,14 +197,6 @@ public void onDrawerOpened(View drawerView) {
selectItem(0);
}
- @Override
- protected void onStop() {
- // Disconnect from Google APIs.
- mGoogleApiClient.disconnect();
-
- super.onStop();
- }
-
@Override
public void onResume() {
super.onResume();
@@ -318,21 +291,9 @@ public void onClick(DialogInterface dialog, int which) {
}
}
})
- .setNegativeButton(R.string.import_recipes_drive_button, new DialogInterface.OnClickListener() {
+ .setNegativeButton(R.string.drive_button, new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
- if (! mGoogleApiClient.isConnected()) {
- Log.d("MainActivity", "Connecting to Google API");
- progressDialog.setMessage("Connecting to Google APIs...");
- progressDialog.setIndeterminate(false);
- progressDialog.setProgressStyle(ProgressDialog.STYLE_SPINNER);
- progressDialog.setCancelable(false);
- progressDialog.show();
- mGoogleApiClient.connect();
- }
- else {
- // Already connected - just show the picker.
- startGoogleDrivePicker();
- }
+ pickFile();
}
})
.setNeutralButton(R.string.cancel, null);
@@ -378,7 +339,6 @@ public void onClick(DialogInterface dialog, int which) {
Snackbar.make(findViewById(R.id.drawer_layout), snack, Snackbar.LENGTH_LONG).show();
updateFragments();
}
-
});
}
@@ -418,60 +378,66 @@ protected void onActivityResult(int requestCode, int resultCode, Intent data) {
Log.d("MainActivity", "Load recipes from file cancelled by user");
}
}
- else if (requestCode == Constants.REQUEST_CONNECT_TO_DRIVE) {
- Log.d("MainActivity", "Result from Google API: " + resultCode);
- if (resultCode == RESULT_OK) {
- // Make sure the app is not already connected or attempting to connect
- if (! mGoogleApiClient.isConnecting() &&
- ! mGoogleApiClient.isConnected()) {
- mGoogleApiClient.connect();
+ else {
+ // If none of the above handle the response, see if the super class handles it.
+ // The DriveActivity superclass handles responses to Google Drive intents.
+ super.onActivityResult(requestCode, resultCode, data);
+ }
+ }
+
+ /**
+ * Called by the DriveActivity when a drive file has been selected by a user.
+ *
+ * @param data
+ */
+ public void onDriveFilePicked(Intent data) {
+ DriveId driveId = data.getParcelableExtra(OpenFileActivityBuilder.EXTRA_RESPONSE_DRIVE_ID);
+ final DriveFile file = Drive.DriveApi.getFile(driveClient, driveId);
+
+ // Callback for when the file has been opened. Checks for success and extracts the contents
+ // of the file.
+ final ResultCallback resultCallback = new ResultCallback() {
+ @Override
+ public void onResult(DriveApi.DriveContentsResult result) {
+ if (! result.getStatus().isSuccess()) {
+ // TODO: Display an error saying file can't be opened
+ return;
}
+ // DriveContents object contains pointers to the actual byte stream.
+ DriveContents contents = result.getDriveContents();
+
+ // Load the recipes in the file.
+ new LoadRecipes(contents.getInputStream(), fileName, ingredientHandler).execute("");
}
- }
- else if (requestCode == Constants.REQUEST_DRIVE_FILE) {
- Log.d("MainActivity", "Result from Google Drive file access: " + resultCode);
- if (resultCode == RESULT_OK) {
- DriveId driveId = data.getParcelableExtra(OpenFileActivityBuilder.EXTRA_RESPONSE_DRIVE_ID);
- final DriveFile file = Drive.DriveApi.getFile(mGoogleApiClient, driveId);
-
- // Callback for when the file has been opened. Checks for success and extracts the contents
- // of the file.
- final ResultCallback resultCallback = new ResultCallback() {
- @Override
- public void onResult(DriveApi.DriveContentsResult result) {
- if (! result.getStatus().isSuccess()) {
- // TODO: Display an error saying file can't be opened
- return;
- }
- // DriveContents object contains pointers to the actual byte stream.
- DriveContents contents = result.getDriveContents();
-
- // Load the recipes in the file.
- new LoadRecipes(contents.getInputStream(), fileName, ingredientHandler).execute("");
- }
- };
-
- // Callback for when file Metadata has been returned - extracts the file name
- // and opens the file.
- ResultCallback metadataCallback = new ResultCallback() {
- @Override
- public void onResult(DriveResource.MetadataResult result) {
- if (! result.getStatus().isSuccess()) {
- // TODO: Display an error saying file can't be opened
- return;
- }
- // Set fileName for use in LoadRecipes.
- fileName = result.getMetadata().getTitle() + result.getMetadata().getFileExtension();
-
- // Open the file.
- file.open(mGoogleApiClient, DriveFile.MODE_READ_ONLY, null).setResultCallback(resultCallback);
- }
- };
+ };
- // Get Metadata for the file.
- file.getMetadata(mGoogleApiClient).setResultCallback(metadataCallback);
+ // Callback for when file Metadata has been returned - extracts the file name
+ // and opens the file.
+ ResultCallback metadataCallback = new ResultCallback() {
+ @Override
+ public void onResult(DriveResource.MetadataResult result) {
+ if (! result.getStatus().isSuccess()) {
+ // TODO: Display an error saying file can't be opened
+ return;
+ }
+ // Set fileName for use in LoadRecipes.
+ fileName = result.getMetadata().getTitle() + result.getMetadata().getFileExtension();
+
+ // Open the file.
+ file.open(driveClient, DriveFile.MODE_READ_ONLY, null).setResultCallback(resultCallback);
}
- }
+ };
+
+ // Get Metadata for the file.
+ file.getMetadata(driveClient).setResultCallback(metadataCallback);
+ }
+
+ @Override
+ public void onDriveFileWritten(Intent data) {
+ Log.d("MainActivity", "File written to drive");
+
+ // Show a snack bar showing that it was exported.
+ ((RecipesFragment) fragmentList.get(0)).recipesExportedSnackbar();
}
@Override
@@ -487,51 +453,8 @@ public void onConfigurationChanged(Configuration newConfig) {
mDrawerToggle.onConfigurationChanged(newConfig);
}
- @Override
- public void onConnected(Bundle bundle) {
- Log.d("MainActivity", "Connected to Google APIs");
- if (progressDialog.isShowing()) {
- Log.d("MainActivity", "Dismissing progress dialog");
- progressDialog.dismiss();
- }
- startGoogleDrivePicker();
- }
-
- public void startGoogleDrivePicker() {
- Log.d("MainActivity", "Starting Google Drive file picker intent");
- IntentSender intentSender = Drive.DriveApi
- .newOpenFileActivityBuilder()
- .build(mGoogleApiClient);
- try {
- startIntentSenderForResult(
- intentSender, Constants.REQUEST_DRIVE_FILE, null, 0, 0, 0);
- } catch (IntentSender.SendIntentException e) {
- e.printStackTrace();
- }
- }
-
- @Override
- public void onConnectionSuspended(int i) {
-
- }
-
- @Override
- public void onConnectionFailed(ConnectionResult result) {
- Log.d("MainActivity", "Google API Connection failed");
- if (result.hasResolution()) {
- try {
- result.startResolutionForResult(this, Constants.REQUEST_CONNECT_TO_DRIVE);
- } catch (IntentSender.SendIntentException e) {
- mGoogleApiClient.connect();
- }
- }
- else {
- GoogleApiAvailability.getInstance().getErrorDialog(this, result.getErrorCode(), Constants.REQUEST_CONNECT_TO_DRIVE).show();
- }
- }
-
/**
- * Private class which handle¬¬s selections in the app drawer and selects the appropriate Fragment
+ * Private class which handles selections in the app drawer and selects the appropriate Fragment
* to display.
*/
private class DrawerItemClickListener implements ListView.OnItemClickListener {
diff --git a/src/com/biermacht/brews/frontend/SettingsActivity.java b/src/com/biermacht/brews/frontend/SettingsActivity.java
index bcb760e..b5d3b94 100644
--- a/src/com/biermacht/brews/frontend/SettingsActivity.java
+++ b/src/com/biermacht/brews/frontend/SettingsActivity.java
@@ -3,8 +3,10 @@
import android.app.ProgressDialog;
import android.content.Context;
import android.content.DialogInterface;
+import android.content.Intent;
import android.os.AsyncTask;
import android.os.Bundle;
+import android.support.design.widget.Snackbar;
import android.support.v7.app.AlertDialog;
import android.util.Log;
import android.view.View;
@@ -123,6 +125,16 @@ public void onNothingSelected(AdapterView> parentView) {
});
}
+ @Override
+ public void onDriveFilePicked(Intent data) {
+ // Not used.
+ }
+
+ @Override
+ public void onDriveFileWritten(Intent data) {
+ Snackbar.make(mainView, R.string.recipes_exported, Snackbar.LENGTH_LONG).show();
+ }
+
@Override
public void onRecipeNotFound() {
// We don't need a recipe for this, so do nothing.
@@ -218,15 +230,21 @@ private AlertDialog.Builder exportRecipes() {
return new AlertDialog.Builder(this)
.setTitle("Export all recipes")
.setMessage("Export all recipes to BeerXML.")
- .setPositiveButton(R.string.export, new DialogInterface.OnClickListener() {
+ .setPositiveButton(R.string.local_storage, new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
new ExportRecipes().execute("");
}
})
+ .setNegativeButton(R.string.drive_button, new DialogInterface.OnClickListener() {
- .setNegativeButton(R.string.cancel, null);
+ public void onClick(DialogInterface dialog, int which) {
+ writeFile(DatabaseAPI.getRecipeList());
+ }
+
+ })
+ .setNeutralButton(R.string.cancel, null);
}
private AlertDialog.Builder finishedExporting(String pathToFile) {
diff --git a/src/com/biermacht/brews/frontend/fragments/RecipesFragment.java b/src/com/biermacht/brews/frontend/fragments/RecipesFragment.java
index 155f269..da2b1e2 100644
--- a/src/com/biermacht/brews/frontend/fragments/RecipesFragment.java
+++ b/src/com/biermacht/brews/frontend/fragments/RecipesFragment.java
@@ -28,7 +28,6 @@
import com.biermacht.brews.R;
import com.biermacht.brews.database.DatabaseAPI;
-import com.biermacht.brews.database.DatabaseInterface;
import com.biermacht.brews.frontend.AddRecipeActivity;
import com.biermacht.brews.frontend.BrewTimerActivity;
import com.biermacht.brews.frontend.DisplayRecipeActivity;
@@ -40,11 +39,11 @@
import com.biermacht.brews.frontend.IngredientActivities.AddMiscActivity;
import com.biermacht.brews.frontend.IngredientActivities.AddYeastActivity;
import com.biermacht.brews.frontend.IngredientActivities.EditRecipeActivity;
-import com.biermacht.brews.frontend.MainActivity;
import com.biermacht.brews.frontend.adapters.DisplayRecipeCollectionPagerAdapter;
import com.biermacht.brews.frontend.adapters.RecipeArrayAdapter;
import com.biermacht.brews.recipe.Recipe;
import com.biermacht.brews.utils.Constants;
+import com.biermacht.brews.utils.DriveActivity;
import com.biermacht.brews.utils.Utils;
import com.biermacht.brews.utils.interfaces.BiermachtFragment;
import com.biermacht.brews.xml.RecipeXmlWriter;
@@ -65,9 +64,6 @@ public class RecipesFragment extends Fragment implements BiermachtFragment {
private AdapterView.OnItemLongClickListener mLongClickListener;
private ArrayList recipeList;
- // Database Interface
- private DatabaseInterface databaseInterface;
-
// Context menu items
private ArrayList menuItems;
@@ -124,9 +120,6 @@ public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle sa
isTablet = true;
}
- // Get database Interface
- databaseInterface = MainActivity.databaseInterface;
-
// Callback which handles the creation and operation of the contextual action bar when
// a Recipe is long-pressed.
mActionModeCallback = new ActionMode.Callback() {
@@ -298,6 +291,10 @@ public boolean onItemLongClick(AdapterView> adapterView, View view, int pos, l
return pageView;
}
+ public void recipesExportedSnackbar() {
+ Snackbar.make(listView, R.string.recipe_exported, Snackbar.LENGTH_LONG).show();
+ }
+
@Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
super.onCreateOptionsMenu(menu, inflater);
@@ -528,7 +525,7 @@ private AlertDialog.Builder exportAlert(final Recipe r) {
return new AlertDialog.Builder(getActivity())
.setTitle("Export recipe")
.setMessage("Export '" + r.getRecipeName() + "' to BeerXML file?")
- .setPositiveButton(R.string.export, new DialogInterface.OnClickListener() {
+ .setPositiveButton(R.string.local_storage, new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
new ExportRecipe(r).execute("");
@@ -537,7 +534,17 @@ public void onClick(DialogInterface dialog, int which) {
}
})
- .setNegativeButton(R.string.cancel, null);
+ .setNeutralButton(R.string.cancel, null)
+ .setNegativeButton(R.string.drive_button, new DialogInterface.OnClickListener() {
+
+ public void onClick(DialogInterface dialog, int which) {
+ ArrayList l = new ArrayList();
+ l.add(r);
+ ((DriveActivity) getActivity()).writeFile(l);
+ mActionMode.finish();
+ }
+
+ });
}
private AlertDialog.Builder finishedExporting(String pathToFile) {
diff --git a/src/com/biermacht/brews/utils/Constants.java b/src/com/biermacht/brews/utils/Constants.java
index 437168b..53ebe67 100644
--- a/src/com/biermacht/brews/utils/Constants.java
+++ b/src/com/biermacht/brews/utils/Constants.java
@@ -82,7 +82,8 @@ public class Constants {
public static final int REQUEST_EDIT_RECIPE = 3;
public static final int REQUEST_IMPORT_FILE = 4;
public static final int REQUEST_CONNECT_TO_DRIVE = 5;
- public static final int REQUEST_DRIVE_FILE = 6;
+ public static final int REQUEST_DRIVE_FILE_OPEN = 6;
+ public static final int REQUEST_DRIVE_FILE_CREATE = 7;
// Possible timer states
public static int PAUSED = 0;
diff --git a/src/com/biermacht/brews/utils/DriveActivity.java b/src/com/biermacht/brews/utils/DriveActivity.java
new file mode 100644
index 0000000..274b9bd
--- /dev/null
+++ b/src/com/biermacht/brews/utils/DriveActivity.java
@@ -0,0 +1,264 @@
+package com.biermacht.brews.utils;
+
+import android.app.ProgressDialog;
+import android.content.Intent;
+import android.content.IntentSender;
+import android.os.Bundle;
+import android.support.v7.app.AppCompatActivity;
+import android.util.Log;
+
+import com.biermacht.brews.recipe.Recipe;
+import com.biermacht.brews.xml.RecipeXmlWriter;
+import com.google.android.gms.common.ConnectionResult;
+import com.google.android.gms.common.GoogleApiAvailability;
+import com.google.android.gms.common.api.GoogleApiClient;
+import com.google.android.gms.common.api.ResultCallback;
+import com.google.android.gms.drive.Drive;
+import com.google.android.gms.drive.DriveApi;
+import com.google.android.gms.drive.DriveContents;
+import com.google.android.gms.drive.MetadataChangeSet;
+
+import java.io.IOException;
+import java.io.OutputStream;
+import java.io.OutputStreamWriter;
+import java.io.Writer;
+import java.util.ArrayList;
+
+/**
+ * Created by casey on 3/6/16.
+ */
+public abstract class DriveActivity extends AppCompatActivity implements GoogleApiClient.ConnectionCallbacks, GoogleApiClient.OnConnectionFailedListener {
+
+ public GoogleApiClient driveClient;
+ private ProgressDialog progressDialog;
+ private int action;
+ private ArrayList recipes;
+
+ private static final int NONE = 0;
+ private static final int FILE_OPEN = 1;
+ private static final int FILE_WRITE = 2;
+
+ // Callback for after creating Drive contents.
+ final ResultCallback driveContentsCallback = new
+ ResultCallback() {
+ @Override
+ public void onResult(DriveApi.DriveContentsResult result) {
+
+ if (! result.getStatus().isSuccess()) {
+ // TODO HANDLE ERROR
+ return;
+ }
+ final DriveContents driveContents = result.getDriveContents();
+
+ // Write content to DriveContents
+ OutputStream outputStream = driveContents.getOutputStream();
+ Writer writer = new OutputStreamWriter(outputStream);
+ Recipe r = new Recipe();
+ try {
+ writer.write(new RecipeXmlWriter(getApplicationContext()).getXmlText(recipes));
+ writer.close();
+ } catch (IOException e) {
+ Log.e("MainActivity", e.getMessage());
+ }
+
+ // Determine the default title for the file.
+ String title = RecipeXmlWriter.generateFileName("all-recipes-");
+ if (recipes.size() == 1) {
+ title = RecipeXmlWriter.generateFileName(recipes.get(0).getRecipeName() + "-");
+ }
+
+ // Start intent to pick and create file.
+ MetadataChangeSet metadataChangeSet = new MetadataChangeSet.Builder()
+ .setTitle(title)
+ .setMimeType("text/xml").build();
+ IntentSender intentSender = Drive.DriveApi
+ .newCreateFileActivityBuilder()
+ .setInitialMetadata(metadataChangeSet)
+ .setInitialDriveContents(result.getDriveContents())
+ .setActivityTitle("Save Recipe(s)")
+ .build(driveClient);
+ try {
+ startIntentSenderForResult(intentSender,
+ Constants.REQUEST_DRIVE_FILE_CREATE,
+ null, 0, 0, 0);
+ } catch (IntentSender.SendIntentException e) {
+ // TODO Handle the exception
+ }
+ }
+ };
+
+ public void onCreate(Bundle savedInstanceState) {
+
+ super.onCreate(savedInstanceState);
+
+ // Create the progress dialog view - displayed when connecting to Google APIs.
+ progressDialog = new ProgressDialog(this);
+ progressDialog.setMessage("Connecting to Google APIs...");
+ progressDialog.setIndeterminate(false);
+ progressDialog.setProgressStyle(ProgressDialog.STYLE_SPINNER);
+ progressDialog.setCancelable(false);
+
+ // Create the connection driveClient.
+ driveClient = new GoogleApiClient.Builder(this)
+ .addApi(Drive.API)
+ .addScope(Drive.SCOPE_FILE)
+ .addConnectionCallbacks(this)
+ .addOnConnectionFailedListener(this)
+ .build();
+ }
+
+ // Abstract methods to be overridden by the subclass. These handle drive events.
+ public abstract void onDriveFilePicked(Intent data);
+
+ public abstract void onDriveFileWritten(Intent data);
+
+ public void connectToDrive() {
+ driveClient.connect();
+ progressDialog.show();
+ }
+
+ @Override
+ protected void onStop() {
+ driveClient.disconnect();
+ super.onStop();
+ }
+
+ public void pickFile() {
+ if (! driveClient.isConnected()) {
+ this.action = FILE_OPEN;
+ connectToDrive();
+ }
+ else {
+ _pickFile();
+ }
+ }
+
+ private void _pickFile() {
+ Log.d("DriveActivity", "Starting Google Drive file picker intent");
+ this.action = NONE;
+ IntentSender i = Drive.DriveApi
+ .newOpenFileActivityBuilder()
+ .build(driveClient);
+ try {
+ this.startIntentSenderForResult(i, Constants.REQUEST_DRIVE_FILE_OPEN, null, 0, 0, 0);
+ } catch (IntentSender.SendIntentException e) {
+ e.printStackTrace();
+ }
+ }
+
+ public void writeFile(ArrayList recipes) {
+ // Store the given recipes so we can write them later.
+ this.recipes = recipes;
+
+ if (! driveClient.isConnected()) {
+ this.action = FILE_WRITE;
+ connectToDrive();
+ }
+ else {
+ _writeFile();
+ }
+ }
+
+ private void _writeFile() {
+ Log.d("DriveActivity", "Writing file to Google Drive.");
+ this.action = NONE;
+ IntentSender i = Drive.DriveApi
+ .newOpenFileActivityBuilder()
+ .build(driveClient);
+
+ Drive.DriveApi.newDriveContents(driveClient)
+ .setResultCallback(driveContentsCallback);
+ }
+
+ protected void onActivityResult(int requestCode, int resultCode, Intent data) {
+
+ switch (requestCode) {
+ case Constants.REQUEST_CONNECT_TO_DRIVE:
+ Log.d("DriveActivity", "Result from Google API: " + resultCode);
+ handleConnectToDrive(resultCode, data);
+ break;
+ case Constants.REQUEST_DRIVE_FILE_OPEN:
+ Log.d("MainActivity", "Result from Google Drive file access: " + resultCode);
+ handleDriveFileOpen(resultCode, data);
+ break;
+ case Constants.REQUEST_DRIVE_FILE_CREATE:
+ Log.d("DriveActivity", "Result from Google Drive file create: " + resultCode);
+ handleDriveFileWritten(resultCode, data);
+ break;
+ default:
+ super.onActivityResult(requestCode, resultCode, data);
+ break;
+ }
+ }
+
+ private void handleConnectToDrive(int resultCode, Intent data) {
+ if (resultCode == RESULT_OK) {
+ // Make sure the app is not already connected or attempting to connect
+ if (! this.driveClient.isConnecting() &&
+ ! this.driveClient.isConnected()) {
+ this.driveClient.connect();
+ }
+ }
+ }
+
+ private void handleDriveFileOpen(int resultCode, Intent data) {
+ if (resultCode == RESULT_OK) {
+ // Pass to the onFilePicked method for the subclass to handle.
+ this.onDriveFilePicked(data);
+ }
+ }
+
+ private void handleDriveFileWritten(int resultCode, Intent data) {
+ if (resultCode == RESULT_OK) {
+ // Pass to the onDriveFileWritten method for the subclass to handle.
+ this.onDriveFileWritten(data);
+ }
+
+ // Clear recipes.
+ this.recipes = null;
+ }
+
+ @Override
+ public void onConnected(Bundle bundle) {
+ Log.d("DriveApiHelper", "Connected to Google APIs");
+ if (progressDialog.isShowing()) {
+ Log.d("DriveApiHelper", "Dismissing progress dialog");
+ progressDialog.dismiss();
+ }
+
+ // Based on the action, call the correct method.
+ switch (this.action) {
+ case FILE_OPEN:
+ _pickFile();
+ break;
+ case FILE_WRITE:
+ _writeFile();
+ break;
+ default:
+ Log.e("DriveApiHelper", "Unrecognized action: " + this.action);
+ break;
+ }
+ }
+
+ @Override
+ public void onConnectionSuspended(int i) {
+
+ }
+
+ @Override
+ public void onConnectionFailed(ConnectionResult result) {
+ Log.d("MainActivity", "Google API Connection failed");
+ if (result.hasResolution()) {
+ try {
+ result.startResolutionForResult(this, Constants.REQUEST_CONNECT_TO_DRIVE);
+ } catch (IntentSender.SendIntentException e) {
+ driveClient.connect();
+ }
+ }
+ else {
+ GoogleApiAvailability.getInstance().getErrorDialog(this, result.getErrorCode(),
+ Constants.REQUEST_CONNECT_TO_DRIVE).show();
+ }
+
+ }
+}
diff --git a/src/com/biermacht/brews/xml/RecipeXmlWriter.java b/src/com/biermacht/brews/xml/RecipeXmlWriter.java
index 3259225..9aa7f5f 100644
--- a/src/com/biermacht/brews/xml/RecipeXmlWriter.java
+++ b/src/com/biermacht/brews/xml/RecipeXmlWriter.java
@@ -19,6 +19,7 @@
import java.io.File;
import java.io.IOException;
+import java.io.StringWriter;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
@@ -51,95 +52,148 @@ public void writeRecipe(Recipe r, String filePrefix) {
this.writeRecipes(list, filePrefix);
}
- public void writeRecipes(List list, String filePrefix) {
+ public Document generateDocument(List list) throws ParserConfigurationException {
// Open the document.
DocumentBuilderFactory docFactory = DocumentBuilderFactory.newInstance();
DocumentBuilder docBuilder;
- try {
- // This throws the exceptions!
- docBuilder = docFactory.newDocumentBuilder();
-
- // Create root element.
- Document doc = docBuilder.newDocument();
- Element rootElement = doc.createElement("RECIPES");
- doc.appendChild(rootElement);
-
- for (Recipe r : list) {
- // Element for this recipe.
- Element recipeElement = doc.createElement("RECIPE");
-
- // Create a mapping of name -> value
- Map map = new HashMap();
- map.put("NAME", r.getRecipeName());
- map.put("VERSION", r.getVersion() + "");
- map.put("TYPE", r.getType());
- map.put("EQUIPMENT", "");
- map.put("BREWER", "");
- map.put("BATCH_SIZE", r.getBeerXmlStandardBatchSize() + "");
- map.put("BOIL_SIZE", r.getBeerXmlStandardBoilSize() + "");
- map.put("BOIL_TIME", r.getBoilTime() + "");
- map.put("EFFICIENCY", r.getEfficiency() + "");
- map.put("NOTES", r.getNotes());
- map.put("OG", r.getOG() + "");
- map.put("FG", r.getFG() + "");
- map.put("DISPLAY_OG", r.getMeasuredOG() + "");
- map.put("DISPLAY_FG", r.getMeasuredFG() + "");
- map.put("FERMENTATION_STAGES", r.getFermentationStages() + "");
- map.put("PRIMARY_AGE", r.getFermentationAge(Recipe.STAGE_PRIMARY) + "");
- map.put("SECONDARY_AGE", r.getFermentationAge(Recipe.STAGE_SECONDARY) + "");
- map.put("TERTIARY_AGE", r.getFermentationAge(Recipe.STAGE_TERTIARY) + "");
- map.put("PRIMARY_TEMP", r.getBeerXmlStandardFermentationTemp(Recipe.STAGE_PRIMARY) + "");
- map.put("SECONDARY_TEMP", r.getBeerXmlStandardFermentationTemp(Recipe.STAGE_SECONDARY) + "");
- map.put("TERTIARY_TEMP", r.getBeerXmlStandardFermentationTemp(Recipe.STAGE_TERTIARY) + "");
- map.put("AGE", r.getBottleAge() + "");
-
- for (Map.Entry e : map.entrySet()) {
- String fieldName = e.getKey();
- String fieldValue = e.getValue();
- Element element = doc.createElement(fieldName);
- element.setTextContent(fieldValue);
- recipeElement.appendChild(element);
- }
-
- // Add elements to recipe.
- recipeElement.appendChild(this.getHopsChild(doc, r.getHopsList()));
- recipeElement.appendChild(this.getFermentablesChild(doc, r.getFermentablesList()));
- recipeElement.appendChild(this.getMiscsChild(doc, r.getMiscList()));
- recipeElement.appendChild(this.getYeastsChild(doc, r.getYeastsList()));
- recipeElement.appendChild(this.getWatersChild(doc, r.getWatersList()));
- recipeElement.appendChild(this.getMashChild(doc, r.getMashProfile()));
- recipeElement.appendChild(this.getStyleChild(doc, r.getStyle()));
-
- // Add recipe to root element.
- rootElement.appendChild(recipeElement);
+
+ // This throws the exceptions!
+ docBuilder = docFactory.newDocumentBuilder();
+
+ // Create root element.
+ Document doc = docBuilder.newDocument();
+ Element rootElement = doc.createElement("RECIPES");
+ doc.appendChild(rootElement);
+
+ for (Recipe r : list) {
+ // Element for this recipe.
+ Element recipeElement = doc.createElement("RECIPE");
+
+ // Create a mapping of name -> value
+ Map map = new HashMap();
+ map.put("NAME", r.getRecipeName());
+ map.put("VERSION", r.getVersion() + "");
+ map.put("TYPE", r.getType());
+ map.put("EQUIPMENT", "");
+ map.put("BREWER", "");
+ map.put("BATCH_SIZE", r.getBeerXmlStandardBatchSize() + "");
+ map.put("BOIL_SIZE", r.getBeerXmlStandardBoilSize() + "");
+ map.put("BOIL_TIME", r.getBoilTime() + "");
+ map.put("EFFICIENCY", r.getEfficiency() + "");
+ map.put("NOTES", r.getNotes());
+ map.put("OG", r.getOG() + "");
+ map.put("FG", r.getFG() + "");
+ map.put("DISPLAY_OG", r.getMeasuredOG() + "");
+ map.put("DISPLAY_FG", r.getMeasuredFG() + "");
+ map.put("FERMENTATION_STAGES", r.getFermentationStages() + "");
+ map.put("PRIMARY_AGE", r.getFermentationAge(Recipe.STAGE_PRIMARY) + "");
+ map.put("SECONDARY_AGE", r.getFermentationAge(Recipe.STAGE_SECONDARY) + "");
+ map.put("TERTIARY_AGE", r.getFermentationAge(Recipe.STAGE_TERTIARY) + "");
+ map.put("PRIMARY_TEMP", r.getBeerXmlStandardFermentationTemp(Recipe.STAGE_PRIMARY) + "");
+ map.put("SECONDARY_TEMP", r.getBeerXmlStandardFermentationTemp(Recipe.STAGE_SECONDARY) + "");
+ map.put("TERTIARY_TEMP", r.getBeerXmlStandardFermentationTemp(Recipe.STAGE_TERTIARY) + "");
+ map.put("AGE", r.getBottleAge() + "");
+
+ for (Map.Entry e : map.entrySet()) {
+ String fieldName = e.getKey();
+ String fieldValue = e.getValue();
+ Element element = doc.createElement(fieldName);
+ element.setTextContent(fieldValue);
+ recipeElement.appendChild(element);
}
- // Write to XML file.
- TransformerFactory transformerFactory = TransformerFactory.newInstance();
- Transformer transformer = transformerFactory.newTransformer();
- DOMSource source = new DOMSource(doc);
+ // Add elements to recipe.
+ recipeElement.appendChild(this.getHopsChild(doc, r.getHopsList()));
+ recipeElement.appendChild(this.getFermentablesChild(doc, r.getFermentablesList()));
+ recipeElement.appendChild(this.getMiscsChild(doc, r.getMiscList()));
+ recipeElement.appendChild(this.getYeastsChild(doc, r.getYeastsList()));
+ recipeElement.appendChild(this.getWatersChild(doc, r.getWatersList()));
+ recipeElement.appendChild(this.getMashChild(doc, r.getMashProfile()));
+ recipeElement.appendChild(this.getStyleChild(doc, r.getStyle()));
+
+ // Add recipe to root element.
+ rootElement.appendChild(recipeElement);
+ }
+ return doc;
+ }
+
+ public String getXmlText(List list) {
+ // Get the generated XML doc.
+ Document doc;
+ try {
+ doc = generateDocument(list);
+ } catch (ParserConfigurationException e) {
+ e.printStackTrace();
+ return null;
+ }
- // Generate date string
- SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd_HH-mm-ss");
- String dateString = dateFormat.format(new Date());
+ DOMSource domSource = new DOMSource(doc);
+ StringWriter writer = new StringWriter();
+ StreamResult result = new StreamResult(writer);
+ TransformerFactory tf = TransformerFactory.newInstance();
+ Transformer transformer = null;
- // Create file object
- File file = getStoragePath(filePrefix + dateString + ".xml");
- StreamResult result = new StreamResult(file);
- Log.d("WriteXmlFile", "Writing XML to:" + file);
+ try {
+ transformer = tf.newTransformer();
+ } catch (TransformerConfigurationException e) {
+ e.printStackTrace();
+ }
- transformer.transform(source, result);
- this.lastFileLocation = file.getAbsolutePath();
+ try {
+ transformer.transform(domSource, result);
+ } catch (TransformerException e) {
+ e.printStackTrace();
+ }
+
+ writer.flush();
+ return writer.toString();
+ }
+ public static String generateFileName(String prefix) {
+ // Generate date string
+ SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd_HH-mm-ss");
+ String dateString = dateFormat.format(new Date());
+
+ return prefix + dateString + ".xml";
+ }
+
+ public void writeRecipes(List list, String filePrefix) {
+ // Get the generated XML doc.
+ Document doc;
+ try {
+ doc = generateDocument(list);
} catch (ParserConfigurationException e) {
e.printStackTrace();
+ return;
+ }
+
+ // Write to XML file.
+ TransformerFactory transformerFactory = TransformerFactory.newInstance();
+ Transformer transformer = null;
+ try {
+ transformer = transformerFactory.newTransformer();
} catch (TransformerConfigurationException e) {
e.printStackTrace();
+ return;
+ }
+ DOMSource source = new DOMSource(doc);
+
+ // Create file object
+ File file = null;
+ try {
+ file = getStoragePath(generateFileName(filePrefix));
} catch (IOException e) {
e.printStackTrace();
+ }
+ StreamResult result = new StreamResult(file);
+ Log.d("WriteXmlFile", "Writing XML to:" + file);
+
+ try {
+ transformer.transform(source, result);
} catch (TransformerException e) {
e.printStackTrace();
}
+ this.lastFileLocation = file.getAbsolutePath();
}
/**