I have a database backup stored in app folder in the drive. Below is the code I have written.
public void startRestore(View view)
{
int EXTERNAL_WRITE_PERMISSION = ContextCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE);
if(Build.VERSION.SDK_INT>= Build.VERSION_CODES.M)
{
if(EXTERNAL_WRITE_PERMISSION != PackageManager.PERMISSION_GRANTED)
{
if (ActivityCompat.shouldShowRequestPermissionRationale(this, Manifest.permission.WRITE_EXTERNAL_STORAGE))
{
Snackbar.make(mLayout, "Write permission is required",
Snackbar.LENGTH_INDEFINITE).setAction("OK", new View.OnClickListener() {
@Override
public void onClick(View view) {
// Request the permission
ActivityCompat.requestPermissions(BackupActivity.this,
new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE},
PERMISSION_REQUEST_STORAGE);
}
}).show();
} else {
ActivityCompat.requestPermissions(this,
new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE},
PERMISSION_REQUEST_STORAGE);
}
}
}
if (backupExists())
{
Log.d("RESTORE: ", "Started restore");
final String driveFileID = sharedPreferences.getString("dbBackupDriveFileID", "");
final DriveFile driveFile = DriveId.decodeFromString(driveFileID).asDriveFile();
Log.d("RESTORE_FileID: ", driveFileID);
final Task<DriveContents> openFileTask = mDriveResourceClient.openFile(driveFile, DriveFile.MODE_READ_ONLY);
openFileTask.continueWithTask(new Continuation<DriveContents, Task<Void>>()
{
@Override
public Task<Void> then(@NonNull Task<DriveContents> task) throws Exception
{
Log.d("RESTORE: ", "open File task");
DriveContents driveContents = task.getResult();
//TODO download file an add to database
InputStream inputStream = driveContents.getInputStream();
byte[] buf = new byte[8192];
int c = 0;
String baseDir = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS).getAbsolutePath();
String fileName = DatabaseHelper.DATABASE_NAME;
Log.d("RESTORE: ", baseDir + "/" +fileName);
File f = new File(baseDir+File.pathSeparator+fileName);
if(f.canWrite())
{
Log.d("RESTORE: ", "File writable");
OutputStream outputStream = new FileOutputStream(f);
while ((c = inputStream.read(buf, 0, buf.length)) > 0)
{
outputStream.write(buf, 0, c);
outputStream.flush();
}
outputStream.close();
}
else
{
Log.d("RESTORE: ", "File not writable");
}
return mDriveResourceClient.discardContents(driveContents);
}
})
.addOnFailureListener(new OnFailureListener()
{
@Override
public void onFailure(@NonNull Exception e)
{
}
});
}
else
{
Toast.makeText(this, "Backup does not exists", Toast.LENGTH_SHORT).show();
}
}
In the above code the the control always reaches to Log.d("RESTORE: ", "File not writable");
. I have the write permissions defined in the manifest and also runtime permission is granted. Also there is no error in the log.
Below is the backup function for reference.
public void startBackup(View view)
{
final ProgressDialog progressDialog = new ProgressDialog(this);
final File currentDB = this.getDatabasePath(DatabaseHelper.DATABASE_NAME);
Log.d("DATABASE: ", currentDB.getAbsolutePath());
Log.d("DATABASE: ", currentDB.getName());
progressDialog.setMessage("Backing Up!!!!");
progressDialog.show();
final Task<DriveFolder> appFolderTask = mDriveResourceClient.getAppFolder();
final Task<DriveContents> createContentsTask = mDriveResourceClient.createContents();
Tasks.whenAll(appFolderTask, createContentsTask)
.continueWithTask(new Continuation<Void, Task<DriveFile>>()
{
@Override
public Task<DriveFile> then(@NonNull Task<Void> task) throws Exception
{
DriveFolder parent = appFolderTask.getResult();
DriveContents contents = createContentsTask.getResult();
InputStream inputStream = null;
try
{
inputStream = new FileInputStream(currentDB);
}
catch (FileNotFoundException e)
{
e.printStackTrace();
}
OutputStream outputStream = contents.getOutputStream();
int c = 0;
byte[] buf = new byte[8192];
if (inputStream != null)
{
while ((c = inputStream.read(buf, 0, buf.length)) > 0)
{
outputStream.write(buf, 0, c);
outputStream.flush();
}
outputStream.close();
}
else
{
Toast.makeText(BackupActivity.this, "Some error occurred", Toast.LENGTH_SHORT).show();
}
MetadataChangeSet changeSet = new MetadataChangeSet.Builder()
.setMimeType("application/x-sqlite3")
.setTitle(currentDB.getName())
.build();
return mDriveResourceClient.createFile(parent, changeSet, contents);
}
})
.addOnSuccessListener(this, new OnSuccessListener<DriveFile>() {
@Override
public void onSuccess(DriveFile driveFile)
{
progressDialog.dismiss();
String driveFileID = driveFile.getDriveId().encodeToString();
String dateTime = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss", Locale.getDefault()).format(new Date());
SharedPreferences.Editor editor = sharedPreferences.edit();
editor.putString("dbBackupDriveFileID", driveFileID);
editor.putString("lastDbBackupTime", dateTime);
editor.apply();
Log.d("DRIVE_FILE", driveFileID);
String d = getString(R.string.last_backup) + dateTime;
textView.setText(d);
Toast.makeText(BackupActivity.this, "Backup Successful. File "+driveFile.getDriveId()
.encodeToString(), Toast.LENGTH_LONG).show();
}
})
.addOnFailureListener(this, new OnFailureListener() {
@Override
public void onFailure(@NonNull Exception e)
{
progressDialog.dismiss();
Log.e("DRIVE ", "Unable to create file", e);
Toast.makeText(BackupActivity.this, "Unable to backup", Toast.LENGTH_SHORT).show();
}
});
}
Instead of using the File f = new File(baseDir+File.pathSeparator+fileName);
I replaced the File usage with an FileOutputStream
.
Modified part of the restore function:
DriveContents driveContents = task.getResult();
//TODO download file an add to database
InputStream inputStream = driveContents.getInputStream();
byte[] buf = new byte[8192];
int c = 0;
if(Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED))
{
Log.d("RESTORE: ", "External DIR mounted");
String baseDir = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS).getAbsolutePath();
String fileName = DatabaseHelper.DATABASE_NAME;
String fileFullName = baseDir + File.separator + fileName;
Log.d("RESTORE: ", fileFullName);
FileOutputStream outputStream;
outputStream = new FileOutputStream(fileFullName, false);
while ((c = inputStream.read(buf, 0, buf.length)) > 0) {
outputStream.write(buf, 0, c);
outputStream.flush();
}
outputStream.close();
}
else
{
Log.d("RESTORE: ", "External DIR not mounted");
}
This solved my issue.