7

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.

Community
  • 1
  • 1
Paritosh
  • 367
  • 5
  • 20

1 Answers1

14

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

seanpj
  • 6,735
  • 2
  • 33
  • 54
  • Appreciate the code. Atleast now I know in which direction to think. Tried to implement it but I am getting a file/folder not found error. Updated the question with the onConnected method code. Interestingly this is the same path I am using to backup (and restore) database in device storage and it works without any problem! – Paritosh Nov 10 '15 at 00:21
  • This might sound naive but the path worked and so did your code with "/data/data/"..... instead of "/data/"! Now trying to reverse the process and get database from app folder... – Paritosh Nov 10 '15 at 00:39
  • The path (\...\...\) I put there is symbolic I have no clue where YOUR database file is, nor what it's name is. The code deals only with uploading the file to the Drive. If you need to download it back, use the DriveId you got from upload above and apply it to the 'read()' method [here](https://github.com/seanpjanson/GDAADemo/blob/master/app/src/main/java/com/spjanson/gdaademo/GDAA.java). – seanpj Nov 10 '15 at 02:22
  • Trying to use the read() method as given but I keep getting the file/folder not found error. This is the code I am using to get drive ID (since there are multiple files), ` MetadataBuffer mdb = result.getMetadataBuffer(); String ID = mdb.get(0).getDriveId(); ` and then passing the ID to read(). Tried with getResourceId() too (after reading one of your replies in SO) but with no luck. – Paritosh Nov 10 '15 at 09:52
  • I have modified the answer to include the full solution up to InputStream. You have to write the input stream to your DB file. It may also be beneficial to play with [this demo](https://github.com/seanpjanson/GDAADemo). – seanpj Nov 10 '15 at 11:59
  • @seanpj,Hi i tried above one.its working fine but one problem in google drive size of the file is 20 kb.After adding lot of item in db it show same 20 kb. – rafeek Oct 07 '17 at 14:04
  • @seanpj Can you help with the same in flutter – M.K. Mandawar Jun 02 '22 at 03:57