Lunchbox
Lunchbox

Reputation: 1550

Dropbox sync / Google drive, how to upload sqlite database

I am trying to upload a sqlite database file to dropbox. This is my code:

public void uploadDb(){
    File public_db_file = null;
    try {
        public_db_file = writeDbToPublicDirectory();
    } catch (IOException e2) {
        e2.printStackTrace();
    }

    DbxFileSystem dbxFs = null;

    try {
        dbxFs = DbxFileSystem.forAccount(mAccount);
    } catch (Unauthorized e1) {
        e1.printStackTrace();
    }

    DbxFile testFile = null;
    try {
        testFile = dbxFs.create(new DbxPath("database_sync.txt"));
    } catch (InvalidPathException e1) {
        e1.printStackTrace();
    } catch (DbxException e1) {
        e1.printStackTrace();
    }
    try {
        testFile.writeFromExistingFile(public_db_file, false);
    } catch (IOException e) {
        e.printStackTrace();
    } finally {
        testFile.close();
    }

}

EDIT (More code)

This function copies my database from the app private dir to a public dir so that I can upload it:

private File writeDbToPublicDirectory() throws IOException {
    // TODO Auto-generated method stub
    File sd = Environment.getExternalStorageDirectory();
    File backupDB = null;
    if (sd.canWrite()) {
        String backupDBPath = "copied_database.db";
        File currentDB = context.getDatabasePath("private_database");
        backupDB = new File(sd, backupDBPath);

        if (currentDB.exists()) {
            FileChannel src = new FileInputStream(currentDB).getChannel();
            FileChannel dst = new FileOutputStream(backupDB).getChannel();
            dst.transferFrom(src, 0, src.size());
            src.close();
            dst.close();
        }
    }
    return backupDB;
} 

The problem is that when I check on my device dropbox, the file size is 0 bytes. The file is created on dropbox, but my database data is not. What am I doing wrong? Thank you in advance

EDIT

I have decided that using Google Drive may be a better option, but I can only upload text files by using the sample applications. Is there any good tutorial or resource that I can use to upload a sqlite database file? I am really badly stuck on this. Please help me with either of these, thank you in advance

Upvotes: 2

Views: 6464

Answers (3)

Tanapruk Tangphianphan
Tanapruk Tangphianphan

Reputation: 803

I modified @Manish Mulimani's code. I make use of some modules in com.google.android.gms.drive.sample.demo which is available from Google Drive API Website. The modules are BaseDemoActivity, ApiClientAsyncTask and EditContentsActivity. Here are the code.

import android.content.Context;
import android.os.Bundle;
import android.util.Log;
import android.webkit.MimeTypeMap;
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.DriveFile;
import com.google.android.gms.drive.DriveFolder;
import com.google.android.gms.drive.MetadataChangeSet;
import com.google.android.gms.drive.DriveApi.DriveContentsResult;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.FileInputStream;
import java.io.IOException;



public class gDriveActivity extends BaseDemoActivity {

    private final static String TAG = "gDriveActivity";



    @Override
    public void onConnected(Bundle connectionHint) {
        super.onConnected(connectionHint);


        // create new contents resource.
        Drive.DriveApi.newDriveContents(getGoogleApiClient()).setResultCallback(driveContentsCallback);
    }


    final private ResultCallback<DriveApi.DriveContentsResult> driveContentsCallback =
            new ResultCallback<DriveApi.DriveContentsResult>() {
                @Override
                public void onResult(DriveApi.DriveContentsResult result) {
                    if (!result.getStatus().isSuccess()) {
                        //if failure
                        showMessage("Error while trying to create new file contents");
                        return;
                    }


                    //change the metadata of the file. by setting title, setMimeType.
                    String mimeType = MimeTypeMap.getSingleton().getExtensionFromMimeType("db");
                    MetadataChangeSet changeSet = new MetadataChangeSet.Builder()
                            .setTitle("mydb")
                            .setMimeType(mimeType)
                            .build();



                    Drive.DriveApi.getAppFolder(getGoogleApiClient())
                            .createFile(getGoogleApiClient(), changeSet, result.getDriveContents()).setResultCallback(fileCallBack);

                }

            };


    final ResultCallback<DriveFolder.DriveFileResult> fileCallBack = new ResultCallback<DriveFolder.DriveFileResult>() {
        @Override
        public void onResult(DriveFolder.DriveFileResult driveFileResult) {

            if (!driveFileResult.getStatus().isSuccess()) {
                Log.v(TAG, "Error while trying to create the file");
                return;
            }
            //Initialize mFile to be processed in AsyncTask
            DriveFile mfile = driveFileResult.getDriveFile();
            new EditContentsAsyncTask(gDriveActivity .this).execute(mfile);

        }
    };

    public class EditContentsAsyncTask extends ApiClientAsyncTask<DriveFile, Void, Boolean> {

        public EditContentsAsyncTask(Context context) {
            super(context);
        }

        @Override
        protected Boolean doInBackgroundConnected(DriveFile... args) {
            DriveFile file = args[0];
            try {

                DriveContentsResult driveContentsResult = file.open(
                        getGoogleApiClient(), DriveFile.MODE_WRITE_ONLY, null).await();


                if (!driveContentsResult.getStatus().isSuccess()) {
                    return false;
                }

                DriveContents driveContents = driveContentsResult.getDriveContents();



                //edit the outputStream
                DatabaseHandler db = new DatabaseHandler(gDriveActivity .this);
                String inFileName = getApplicationContext().getDatabasePath(db.getDatabaseName()).getPath();
                FileInputStream is = new FileInputStream(inFileName);
                BufferedInputStream in = new BufferedInputStream(is);
                byte[] buffer = new byte[8 * 1024];

                BufferedOutputStream out = new BufferedOutputStream(driveContents.getOutputStream());
                int n = 0;
                while ((n = in.read(buffer)) > 0) {
                    out.write(buffer, 0, n);
                }
                in.close();


                com.google.android.gms.common.api.Status status =
                        driveContents.commit(getGoogleApiClient(), null).await();
                return status.getStatus().isSuccess();
            } catch (IOException e) {
                Log.e(TAG, "IOException while appending to the output stream", e);
            }
            return false;
        }

        @Override
        protected void onPostExecute(Boolean result) {
            if (!result) {
                showMessage("Error while editing contents");
                return;
            }
            showMessage("Successfully edited contents");
        }
    }


}

Upvotes: 3

Manish Mulimani
Manish Mulimani

Reputation: 17615

I was able to backup the database using Google Drive API. I have used the byte array to copy the contents. Following is the Activity code, which creates a new file on Google Drive root folder and copies the sqlite db content. I've added comments wherever required. Let me know whether it helps.

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;

import com.google.android.gms.common.ConnectionResult;
import com.google.android.gms.common.GooglePlayServicesUtil;
import com.google.android.gms.common.api.GoogleApiClient;
import com.google.android.gms.common.api.GoogleApiClient.ConnectionCallbacks;
import com.google.android.gms.common.api.GoogleApiClient.OnConnectionFailedListener;
import com.google.android.gms.common.api.ResultCallback;
import com.google.android.gms.common.api.Status;
import com.google.android.gms.drive.Contents;
import com.google.android.gms.drive.Drive;
import com.google.android.gms.drive.DriveFile;
import com.google.android.gms.drive.DriveApi.ContentsResult;
import com.google.android.gms.drive.DriveFolder.DriveFileResult;
import com.google.android.gms.drive.MetadataChangeSet;

import android.app.Activity;
import android.app.Dialog;
import android.app.DialogFragment;
import android.content.ContentValues;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.IntentSender.SendIntentException;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteDatabase.CursorFactory;
import android.database.sqlite.SQLiteOpenHelper;
import android.os.Bundle;
import android.provider.BaseColumns;
import android.util.Log;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.webkit.MimeTypeMap;

public class MainActivity extends Activity implements ConnectionCallbacks, OnConnectionFailedListener {

    private static final String TAG = "MainActivity";
    private GoogleApiClient api;
    private boolean mResolvingError = false;
    private DriveFile mfile;
    private static final int DIALOG_ERROR_CODE =100; 
    private static final String DATABASE_NAME = "person.db";
    private static final String GOOGLE_DRIVE_FILE_NAME = "sqlite_db_backup";

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        // Create the Drive API instance
        api = new GoogleApiClient.Builder(this).addApi(Drive.API).addScope(Drive.SCOPE_FILE).
                addConnectionCallbacks(this).addOnConnectionFailedListener(this).build();
    }

    @Override
    public void onStart() {
        super.onStart();
        if(!mResolvingError) {
            api.connect(); // Connect the client to Google Drive
        }
    }

    @Override
    public void onStop() {
        super.onStop();
        api.disconnect(); // Disconnect the client from Google Drive 
    }

    @Override
    public void onConnectionFailed(ConnectionResult result) {
        Log.v(TAG, "Connection failed");
        if(mResolvingError) { // If already in resolution state, just return.
            return;
        } else if(result.hasResolution()) { // Error can be resolved by starting an intent with user interaction
            mResolvingError = true;
            try {
                result.startResolutionForResult(this, DIALOG_ERROR_CODE);
            } catch (SendIntentException e) {
                e.printStackTrace();
            }
        } else { // Error cannot be resolved. Display Error Dialog stating the reason if possible.
            ErrorDialogFragment fragment = new ErrorDialogFragment();
            Bundle args = new Bundle();
            args.putInt("error", result.getErrorCode());
            fragment.setArguments(args);
            fragment.show(getFragmentManager(), "errordialog");
        }
    }

    @Override
    public void onActivityResult(int requestCode, int resultCode, Intent data) {
        if(requestCode == DIALOG_ERROR_CODE) {
            mResolvingError = false;
            if(resultCode == RESULT_OK) { // Error was resolved, now connect to the client if not done so.
                if(!api.isConnecting() && !api.isConnected()) {
                    api.connect();
                }
            }
        }
    }

    @Override
    public void onConnected(Bundle connectionHint) {
        Log.v(TAG, "Connected successfully");

        /* Connection to Google Drive established. Now request for Contents instance, which can be used to provide file contents.
           The callback is registered for the same. */  
        Drive.DriveApi.newContents(api).setResultCallback(contentsCallback);
    }

    final private ResultCallback<ContentsResult> contentsCallback = new ResultCallback<ContentsResult>() {

        @Override
        public void onResult(ContentsResult result) {
            if (!result.getStatus().isSuccess()) {
                Log.v(TAG, "Error while trying to create new file contents");
                return;
            }

            String mimeType = MimeTypeMap.getSingleton().getExtensionFromMimeType("db"); 
            MetadataChangeSet changeSet = new MetadataChangeSet.Builder()
                    .setTitle(GOOGLE_DRIVE_FILE_NAME) // Google Drive File name
                    .setMimeType(mimeType)  
                    .setStarred(true).build();
            // create a file on root folder
            Drive.DriveApi.getRootFolder(api)
                    .createFile(api, changeSet, result.getContents())
                    .setResultCallback(fileCallback);   
        }

    };

    final private ResultCallback<DriveFileResult> fileCallback = new ResultCallback<DriveFileResult>() {

        @Override
        public void onResult(DriveFileResult result) {
            if (!result.getStatus().isSuccess()) {
                Log.v(TAG, "Error while trying to create the file");
                return;
            }
            mfile = result.getDriveFile();
            mfile.openContents(api, DriveFile.MODE_WRITE_ONLY, null).setResultCallback(contentsOpenedCallback);
        }
    };

    final private ResultCallback<ContentsResult> contentsOpenedCallback = new ResultCallback<ContentsResult>() {

        @Override
        public void onResult(ContentsResult result) {

            if (!result.getStatus().isSuccess()) {
                Log.v(TAG, "Error opening file");
                return;
            }

            try {
                FileInputStream is = new FileInputStream(getDbPath());
                BufferedInputStream in = new BufferedInputStream(is);
                byte[] buffer = new byte[8 * 1024];
                Contents content = result.getContents();
                BufferedOutputStream out = new BufferedOutputStream(content.getOutputStream());
                int n = 0;
                while( ( n = in.read(buffer) ) > 0 ) {
                    out.write(buffer, 0, n);
                }

                in.close();
                mfile.commitAndCloseContents(api, content).setResultCallback(new ResultCallback<Status>() {
                    @Override
                    public void onResult(Status result) {
                        // Handle the response status
                    }
                });
            } catch (FileNotFoundException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            } catch (IOException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }

    };

    private File getDbPath() {
        return this.getDatabasePath(DATABASE_NAME);
    }

    @Override
    public void onConnectionSuspended(int cause) {
        // TODO Auto-generated method stub
        Log.v(TAG, "Connection suspended");

    }

    public void onDialogDismissed() {
        mResolvingError = false;
    }

    public static class ErrorDialogFragment extends DialogFragment {
        public ErrorDialogFragment() {}

        public Dialog onCreateDialog(Bundle savedInstanceState) {
            int errorCode = this.getArguments().getInt("error");
            return GooglePlayServicesUtil.getErrorDialog(errorCode, this.getActivity(), DIALOG_ERROR_CODE);
        }

        public void onDismiss(DialogInterface dialog) {
            ((MainActivity) getActivity()).onDialogDismissed();
        }
    }
}

Upvotes: 11

Related Questions