Backup/Restore SQLlite Database to Google Drive app folder

Paritosh picture Paritosh · Nov 9, 2015 · Viewed 8.6k times · Source

I am trying to incorporate the functionality to backup and restore the app database to google drives app folder (NOT visible to the user). I went through the basic setup guide setup guide given for android and can get the user to authorize the app and reach to the point where onConnected method is being called.

The problem that I am facing is, I am not sure how to go about 'sending' the database file (.db) from device to google drive app folder. Google has shared snippet for creating a new file but that's about it. I did find a previously asked question vaguely similar to what I am looking for Google drive to back up and restore database and shared preferences of Android application but then again not what I am looking for.

Searching google doesn't return any helpful links possibly because this is relatively newer api.

UPDATE 1:

Sharing the onConnected() code,

    public void onConnected(Bundle bundle) {
    Toast.makeText(GoogleSignIn.this, "In onConnected activity", Toast.LENGTH_SHORT).show();

    // Testing to see if database is indeed uploaded to google drive app folder
    String db_name = "XXX_DB";
    String currentDBPath = "/data/" + "com.abc.efg" + "/databases/" + db_name;
    saveToDrive(
            Drive.DriveApi.getAppFolder(mGoogleApiClientDrive),
            "XXX_DB.db",
            "application/x-sqlite3",
            new java.io.File(currentDBPath)
    );
}

UPDATE 2:

The solution shared below works perfectly for uploading database to google drive app folder. For those who might face similar problem try changing the database path to "/data/data/com.abc.efg/databases/" + db_name instead of "/data/com.abc.efg/databases/" + db_name

Next step is to be able to retrieve and restore database from google drive app folder. Shall update this question if I am able to get it working.

Answer

seanpj picture seanpj · Nov 9, 2015

Assuming, you're have a path to your MyDbFile.db file, you can use a construct like this:

 ... 
 saveToDrive(
   Drive.DriveApi.getAppFolder(getGoogleApiClient()),
   "MyDbFile.db", 
   "application/x-sqlite3",
   new java.io.File("\...\...\...\MyDbFile.db")
 );
 ...

DriveId mDriveId;
/******************************************************************
 * create file in GOODrive
 * @param pFldr parent's ID
 * @param titl  file name
 * @param mime  file mime type  (application/x-sqlite3)
 * @param file  file (with content) to create
 */
void saveToDrive(final DriveFolder pFldr, final String titl,
                 final String mime, final java.io.File file) {
  if (getGoogleApiClient() != null && pFldr != null && titl != null && mime != null && file != null) try {
    // create content from file
    Drive.DriveApi.newDriveContents(getGoogleApiClient()).setResultCallback(new ResultCallback<DriveContentsResult>() {
      @Override
      public void onResult(DriveContentsResult driveContentsResult) {
        DriveContents cont = driveContentsResult != null && driveContentsResult.getStatus().isSuccess() ?
          driveContentsResult.getDriveContents() : null;

        // write file to content, chunk by chunk
        if (cont != null) try {
          OutputStream oos = cont.getOutputStream();
          if (oos != null) try {
            InputStream is = new FileInputStream(file);
            byte[] buf = new byte[4096];
            int c;
            while ((c = is.read(buf, 0, buf.length)) > 0) {
              oos.write(buf, 0, c);
              oos.flush();
            }
          }
          finally { oos.close();}

          // content's COOL, create metadata
          MetadataChangeSet meta = new Builder().setTitle(titl).setMimeType(mime).build();

          // now create file on GooDrive
          pFldr.createFile(getGoogleApiClient(), meta, cont).setResultCallback(new ResultCallback<DriveFileResult>() {
            @Override
            public void onResult(DriveFileResult driveFileResult) {
              if (driveFileResult != null && driveFileResult.getStatus().isSuccess()) {
                DriveFile dFil = driveFileResult != null && driveFileResult.getStatus().isSuccess() ?
                  driveFileResult.getDriveFile() : null;
                if (dFil != null) {
                  // BINGO , file uploaded
                  dFil.getMetadata(getGoogleApiClient()).setResultCallback(new ResultCallback<MetadataResult>() {
                    @Override
                    public void onResult(MetadataResult metadataResult) {
                      if (metadataResult != null && metadataResult.getStatus().isSuccess()) {
                        DriveId mDriveId = metadataResult.getMetadata().getDriveId();
                      }
                    }
                  });
                }
              } else { /* report error */     }
            }
          });
        } catch (Exception e) { e.printStackTrace(); }
      }
    });
  } catch (Exception e) { e.printStackTrace(); }
}

/*******************************************************************
 * get file contents
 */
void readFromGooDrive() {
  byte[] buf = null;
  if (getGoogleApiClient() != null && getGoogleApiClient().isConnected()) try {
    DriveFile df = Drive.DriveApi.getFile(getGoogleApiClient(), mDriveId);
    df.open(getGoogleApiClient(), DriveFile.MODE_READ_ONLY, null)
      .setResultCallback(new ResultCallback<DriveContentsResult>() {
      @Override
      public void onResult(DriveContentsResult driveContentsResult) {
        if ((driveContentsResult != null) && driveContentsResult.getStatus().isSuccess()) {
          DriveContents cont = driveContentsResult.getDriveContents();
          // DUMP cont.getInputStream() to your DB file
          cont.discard(getGoogleApiClient());    // or cont.commit();  they are equiv if READONLY
        }
      }
    });
  } catch (Exception e) { e.printStackTrace(); }
}

Good Luck