I want to take photo 0.1 seconds-one photo. Then, I can get 10 pictures in 1 seconds.
but, I implement takePhoto() preference cameraX in android developer site.
It is working but not expected.
Because takePhoto() method is called 0.1 seconds but callback listener is more time because of making bitmap, saving file(I guess).
so, I want to implement fast burst(or continuous shooting)camera mode.
However, it is hard to find references.
please help me.
[Call takePhoto()]
binding.imageCaptureButton.setOnClickListener {
val thread = Thread(Runnable {
var overtime = (System.currentTimeMillis() - pressedTime).toInt()
while(!isCaptureDone) {
try {
Log.d(TAG, "Thread: picNum = $picNum")
Log.d(TAG, "Thread: isCaptureDone = $isCaptureDone")
takePhoto()
Thread.sleep(shootMills) // 0.1seconds
overtime = (System.currentTimeMillis() - pressedTime).toInt()
if(overtime >= limitTime || picNum >= maxPicNum) {
pressedTime = 0
isCaptureDone = true
val msg = if(overtime >= limitTime) "over ${limitTime/1000} seconds" else "Take picture over {maxPicNum}"
Log.d(TAG, "onCreate: $msg")
runOnUiThread { alertDialog(msg) }
return#Runnable
}
} catch (e: InterruptedException) {
Log.e(TAG, "Thread Error : ${e.printStackTrace()}")
}
}
})
}
[takePhoto()]
private fun takePhoto() {
// Get a stable reference of the modifiable image capture use case
val imageCapture = cameraManager.getImageCapture() ?: return
// Create time stamped name and MediaStore entry.
val name = SimpleDateFormat(FILENAME_FORMAT, Locale.US)
.format(System.currentTimeMillis())
val contentValues = ContentValues().apply {
put(MediaStore.MediaColumns.DISPLAY_NAME, name)
put(MediaStore.MediaColumns.MIME_TYPE, "image/jpeg")
if(Build.VERSION.SDK_INT > Build.VERSION_CODES.P) {
put(MediaStore.Images.Media.RELATIVE_PATH, "Pictures/CameraX-Image")
}
}
// Create output options object which contains file + metadata
val outputOptions = if(saveInGallery) ImageCapture.OutputFileOptions
.Builder(contentResolver,
MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
contentValues)
.build()
else {
val dir = File(filePath)
if(!dir.exists()) dir.mkdirs()
val fileData = File(filePath, name)
ImageCapture.OutputFileOptions.Builder(fileData).build()
}
//////////// v 1 ////////////////
if(firstSol && !saveInGallery) {
imageCapture.takePicture(ContextCompat.getMainExecutor(this), object :
ImageCapture.OnImageCapturedCallback() {
override fun onCaptureSuccess(image: ImageProxy) {
val bitmap = imageProxyToBitmap(image)
val file1 = convertBitmapToFile(bitmap, name + "__1") // 80.7 KB
val options = BitmapFactory.Options()
options.inSampleSize = 2
val bitmap3 = BitmapFactory.decodeFile(file1.absolutePath, options)
val file3 = convertBitmapToFile(bitmap3, name + "__3") // 7 KB
Log.d(TAG, "onCaptureSuccess: picNum = $picNum")
Log.d(TAG, "onCaptureSuccess: isCaptureDone = $isCaptureDone")
picNum += 2
image.close()
if (isCaptureDone) {
Log.d(TAG, "onCaptureSuccess: isCaptureDone")
cameraManager.stopCamera()
Log.d(TAG, "onCaptureSuccess: stopCamera")
return
}
super.onCaptureSuccess(image)
}
override fun onError(exception: ImageCaptureException) {
super.onError(exception)
Log.d(TAG, "onError: get Bitmap error: " + exception.message)
}
})
} else {
//////////// Solve 2 ////////////////
// // Set up image capture listener, which is triggered after photo has
// // been taken
imageCapture.takePicture(
outputOptions,
ContextCompat.getMainExecutor(this),
object : ImageCapture.OnImageSavedCallback {
override fun onError(exc: ImageCaptureException) {
Log.e(TAG, "Photo capture failed: ${exc.message}", exc)
}
override fun
onImageSaved(output: ImageCapture.OutputFileResults) {
picNum += 1
if (isCaptureDone) {
Log.d(TAG, "onCaptureSuccess: isCaptureDone")
cameraManager.stopCamera()
Log.d(TAG, "onCaptureSuccess: stopCamera")
return
}
}
}
)
}
}
Related
I've succesfully capture image with CameraX into JPEG files. The problem is the file size is big. On an Android powered walki talkie (Android 11), the result is typically 4 to 6 MB, so I'd like to resize it.
Here's my code:
fun takePhoto() {
val FILENAME_FORMAT = "ddMMyyyy_HHmmss"
val capturedContentValues = ContentValues()
capturedContentValues.put(MediaStore.MediaColumns.DISPLAY_NAME,
"CARAKA_"+SimpleDateFormat(FILENAME_FORMAT, Locale.US).format(System.currentTimeMillis()))
capturedContentValues.put(MediaStore.MediaColumns.RELATIVE_PATH, Environment.DIRECTORY_DCIM+"/TESTAPP")
capturedContentValues.put(MediaStore.MediaColumns.MIME_TYPE, "image/jpeg")
val outputOptions= ImageCapture.OutputFileOptions.Builder(
context.contentResolver,
MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
capturedContentValues
).build()
imageCapture.takePicture(
outputOptions,
ContextCompat.getMainExecutor(context),
object : ImageCapture.OnImageSavedCallback {
override fun onError(exc: ImageCaptureException) {
Toast.makeText(context,"Photo capture failed: ${exc.message}", Toast.LENGTH_SHORT).show()
}
override fun onImageSaved(output: ImageCapture.OutputFileResults) {
val theFile = getFile(context, output.savedUri!!)
val capturedBitmap = BitmapFactory.decodeFile(theFile!!.absolutePath)
val resizedBitmap = getResizedBitmap(capturedBitmap, 1024)
val fout = FileOutputStream(theFile.absolutePath)
resizedBitmap.compress(Bitmap.CompressFormat.JPEG, 90, fout)
fout.flush()
fout.close()
}
})
}
fun getResizedBitmap(image: Bitmap, maxSize: Int): Bitmap {
var width = image.width
var height = image.height
val bitmapRatio = width.toFloat() / height.toFloat()
if (bitmapRatio > 1) {
width = maxSize
height = (width / bitmapRatio).toInt()
} else {
height = maxSize
width = (height * bitmapRatio).toInt()
}
return Bitmap.createScaledBitmap(image, width, height, true)
}
#Throws(IOException::class)
fun getFile(context: Context, uri: Uri): File? {
val destinationFilename =
File(context.filesDir.path + File.separatorChar + queryName(context, uri))
try {
context.contentResolver.openInputStream(uri).use { ins ->
createFileFromStream(
ins!!,
destinationFilename
)
}
} catch (ex: java.lang.Exception) {
Log.e("Save File", ex.message!!)
ex.printStackTrace()
}
return destinationFilename
}
fun createFileFromStream(ins: InputStream, destination: File?) {
try {
FileOutputStream(destination).use { os ->
val buffer = ByteArray(4096)
var length: Int
while (ins.read(buffer).also { length = it } > 0) {
os.write(buffer, 0, length)
}
os.flush()
}
} catch (ex: java.lang.Exception) {
Log.e("Save File", ex.message!!)
ex.printStackTrace()
}
}
private fun queryName(context: Context, uri: Uri): String {
val returnCursor: Cursor = context.contentResolver.query(uri, null, null, null, null)!!
val nameIndex: Int = returnCursor.getColumnIndex(OpenableColumns.DISPLAY_NAME)
returnCursor.moveToFirst()
val name: String = returnCursor.getString(nameIndex)
returnCursor.close()
return name
}
Those saved JPEGs size is still within 4 to 6 MB. Not reduced into hundreds KB. What's wrong here?
Instead of resizing it afterwards, another thing you can try is taking a smaller picture. You can set the target resolution to be lower: https://developer.android.com/reference/androidx/camera/core/ImageCapture.Builder#setTargetResolution(android.util.Size)
Why I can't get pictureLatitude,pictureDateTime,pictureLatitude,pictureDateTime value?
They all null?
But I can get outputFileResults,byteArrayInputStream values.
Log.d(TAG, "filePath: $filePath") print=>filePath:
/external/images/media/1000000030 . But at my real mobile phone, the
photo's path is storage/emulated/0/Pictures/CameraX-Image.
====================================================================
==========================================
private fun takePhoto() {
val imageCapture2 = imageCapture1 ?: return
val name =
SimpleDateFormat(FILENAME_FORMAT, Locale.TAIWAN).format(System.currentTimeMillis())
val contentValues = ContentValues().apply {
put(MediaStore.MediaColumns.DISPLAY_NAME, name)
put(MediaStore.MediaColumns.MIME_TYPE, "image/jpeg")
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
put(MediaStore.Images.Media.RELATIVE_PATH, "Pictures/CameraX-Image")
}
}
val outputFileOptions = ImageCapture.OutputFileOptions.Builder(
context?.contentResolver!!,
MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
contentValues
).build()
imageCapture2.takePicture(
outputFileOptions,
ContextCompat.getMainExecutor(requireContext()),
object : ImageCapture.OnImageSavedCallback {
#RequiresApi(Build.VERSION_CODES.Q)
override fun onImageSaved(outputFileResults: ImageCapture.OutputFileResults) {
val msg = "Photo capture succeeded: ${outputFileResults.savedUri}"
Toast.makeText(requireContext(), msg, Toast.LENGTH_SHORT).show()
Log.d(TAG, "onImageSaved: $msg")
val filePath = outputFileResults.savedUri?.path ?: return
Log.d(TAG, "filePath: $filePath")
val originalUri =
MediaStore.setRequireOriginal(outputFileResults.savedUri!!)
Log.d(TAG, "originalUri: $originalUri")
val byteArrayInputStream =
outputFileResults.savedUri?.path?.byteInputStream() ?: return
Log.d(TAG, "byteArrayInputStream:$byteArrayInputStream ")
val exif = ExifInterface(byteArrayInputStream)
val pictureLatitude = exif.getAttribute(ExifInterface.TAG_GPS_LATITUDE)
val pictureDateTime = exif.getAttribute(ExifInterface.TAG_DATETIME)
val latLong = exif.latLong
val altitude = exif.getAltitude(0.0)
Log.d(TAG, "pictureLatitude: $pictureLatitude")
Log.d(TAG, "pictureDateTime: $pictureDateTime")
Log.d(TAG, "latLong: $latLong")
Log.d(TAG, "altitude: $altitude")
println(pictureLatitude)
}
override fun onError(exception: ImageCaptureException) {
Log.e(TAG, "Photo capture failed: ${exception.message}", exception)
}
})
}
I am trying to save video, created from custom application, to the specific folder inside DCIM folder, side by side to original camera folder.
private fun recordVideo() {
val intent = Intent(MediaStore.ACTION_VIDEO_CAPTURE)
takeVideo.launch(intent)
}
private val takeVideo = registerForActivityResult(
ActivityResultContracts.StartActivityForResult()
) {
if (it.resultCode == Activity.RESULT_OK) {
Log.i(
"VIDEO_RECORD_TAG ", "Video is available at ${
it.data?.data?.let { it1 -> getRealPathFromURI(it1) }
}"
)
saveMediaFile(
it.data?.data?.let { it1 -> getRealPathFromURI(it1) }, "MyVideoName"
)
}
}
private fun saveMediaFile(filePath: String?, fileName: String) {
filePath?.let {
val values = ContentValues().apply {
put(MediaStore.Video.Media.DISPLAY_NAME, fileName)
val mExtension = MimeTypeMap.getFileExtensionFromUrl(filePath)
put(MediaStore.Video.Media.MIME_TYPE, MimeTypeMap.getSingleton().getMimeTypeFromExtension(mExtension))
put(MediaStore.Video.Media.RELATIVE_PATH, Environment.DIRECTORY_MOVIES + "/${getString(R.string.app_name)}/")
put(MediaStore.Video.Media.IS_PENDING, 1)
}
val fileUri = contentResolver.insert(
MediaStore.Video.Media.getContentUri(MediaStore.VOLUME_EXTERNAL_PRIMARY),
values
)
fileUri?.let {
contentResolver.openFileDescriptor(fileUri, "w").use { descriptor ->
descriptor?.let {
FileOutputStream(descriptor.fileDescriptor).use { out ->
val videoFile = File(filePath)
FileInputStream(videoFile).use { inputStream ->
val buf = ByteArray(8192)
while (true) {
val sz = inputStream.read(buf)
if (sz <= 0) break
out.write(buf, 0, sz)
}
}
}
}
}
values.clear()
values.put(MediaStore.Video.Media.IS_PENDING, 0)
contentResolver.update(fileUri, values, null, null)
}
}
}
private fun getRealPathFromURI(contentUri: Uri): String? {
var cursor: Cursor? = null
return try {
val proj = arrayOf(MediaStore.Images.Media.DATA)
cursor = contentResolver.query(contentUri, proj, null, null, null)
val columnIndex = cursor?.getColumnIndexOrThrow(MediaStore.Images.Media.DATA)
cursor?.moveToFirst()
columnIndex?.let { cursor?.getString(it) }
} catch (e: Exception) {
Log.e("TAG", "getRealPathFromURI Exception : $e")
""
} finally {
cursor?.close()
}
}
Using this code, folder is created, video is stored as well, but in camera folder I have the same video with original name.
I would like to have only custom created folder with stored videos.
Any suggestion ?
Thanks
I want to send a video to the telegram app via Intent but when I send it, it sends as a file, (same happens with images). Is there any trick to specify how you want to send it? (Because from the gallery it sends the same video playable)
function for sending via Intent
private fun shareItem(fileName: String) {
Log.i(TAG, "shareItem: ")
val videoContentUri = FileProvider.getUriForFile(requireContext(),
"${activity?.applicationContext?.packageName}.provider",
File(LocalFilesRepository.getFullVideoPath(fileName, requireContext()))
)
Log.i("TAG", "shareItem: $videoContentUri")
val shareIntent: Intent = Intent().apply {
action = Intent.ACTION_SEND
flags = Intent.FLAG_GRANT_READ_URI_PERMISSION
putExtra(Intent.EXTRA_STREAM, videoContentUri)
type = "video/mp4"
}
startActivity(Intent.createChooser(shareIntent, resources.getText(R.string.send_to)))
}
...
fun getFullVideoPath(fileName: String, context: Context) =
context.getExternalFilesDir(Environment.DIRECTORY_MOVIES).toString() + File.separatorChar + fileName
videoContentUri looks like this content://com.dmytroa.appname.provider/external_files/emulated/0/Android/data/com.dmytroa.appname/files/Movies/1625360538459.mp4
If someone is interested I solved it by just saving a file temporarily at the public storage and then returning Uri from Mediastore.
fun createTemporaryCopyInPublicStorage(file: File, context: Context): Uri? {
val fileName = "tmp"
return if(Build.VERSION.SDK_INT >= 29) {
val uri = findCreatedTemporaryUri(context, fileName, TEMPORARY_DIR_Q)
copyVideoQAndAbove(context, file, uri, fileName, TEMPORARY_DIR_Q)
} else {
val uri = findCreatedTemporaryUri(context, fileName, TEMPORARY_DIR_BELOWQ)
copyVideoBelowQ(context, file, uri, fileName, TEMPORARY_DIR_BELOWQ)
}
}
private fun findCreatedTemporaryUri(context: Context, fileName: String, path: String): Uri? {
val collection = if(Build.VERSION.SDK_INT >= 29) {
MediaStore.Video.Media.getContentUri(MediaStore.VOLUME_EXTERNAL_PRIMARY)
} else {
MediaStore.Video.Media.EXTERNAL_CONTENT_URI
}
val selection = if (Build.VERSION.SDK_INT >= 29) {
"${MediaStore.Video.Media.TITLE} = ? " +
"AND " +
"${MediaStore.Video.Media.RELATIVE_PATH} = ? "
} else {
"${MediaStore.Video.Media.TITLE} = ? " +
"AND " +
"${MediaStore.Video.Media.DATA} = ? "
}
val args = if (Build.VERSION.SDK_INT >= 29) {
arrayOf(fileName, path)
} else {
arrayOf(fileName, File(path, fileName).absolutePath)
}
context.contentResolver.query(
collection,
arrayOf(MediaStore.Video.Media._ID
),
selection,
args,
null
).use { cursor ->
return if (cursor != null && cursor.moveToFirst()) {
val columnIndexID = cursor.getColumnIndexOrThrow(MediaStore.Video.Media._ID)
val id = cursor.getLong(columnIndexID)
Log.i(TAG, "findCreatedTemporaryUri: " +
"contentUri was already added $id $path $fileName")
Uri.withAppendedPath(MediaStore.Video.Media.EXTERNAL_CONTENT_URI, "$id")
} else {
null
}
}
}
#RequiresApi(Build.VERSION_CODES.Q)
private fun copyVideoQAndAbove(context: Context,
fileToCopy: File,
uri: Uri?,
fileName: String,
relPath: String): Uri? {
val contentDetails = ContentValues().apply {
put(MediaStore.Video.Media.IS_PENDING, 1)
}
val contentUri = if (uri != null) {
context.contentResolver.update(uri, contentDetails, null, null)
uri
} else {
Log.i(TAG, "saveVideoQAndAbove: contentUri insert")
contentDetails.apply {
put(MediaStore.Video.Media.DISPLAY_NAME, fileName)
put(MediaStore.Video.Media.MIME_TYPE, "video/mp4")
put(MediaStore.Video.Media.RELATIVE_PATH, relPath)
}
val collection = MediaStore.Video.Media.getContentUri(MediaStore.VOLUME_EXTERNAL_PRIMARY)
context.contentResolver.insert(collection, contentDetails)
}
return contentUri?.let { createdUri ->
try {
context.contentResolver.openFileDescriptor(createdUri, "w").use { pfd ->
ParcelFileDescriptor.AutoCloseOutputStream(pfd).write(fileToCopy.readBytes())
}
} catch (e: IOException) {
e.printStackTrace()
}
contentDetails.clear()
contentDetails.put(MediaStore.Video.Media.IS_PENDING, 0)
context.contentResolver.update(createdUri, contentDetails, null, null)
createdUri
}
}
private fun copyVideoBelowQ(context: Context,
fileToCopy: File,
uri: Uri?,
fileName: String,
dstParentPath: String): Uri? {
val dstDir = File(dstParentPath)
if (!dstDir.exists())
dstDir.mkdirs()
val fileToCreate = File(dstDir, fileName)
fileToCreate.delete()
fileToCreate.createNewFile()
Log.i(TAG, "saveVideo: created ${fileToCreate.name}")
try {
fileToCopy.inputStream().use { input ->
fileToCreate.outputStream().use { output ->
input.copyTo(output, 2 * 1024)
Log.i(TAG, "saveVideo: finished ${fileToCreate.path}")
}
}
return uri ?: let {
val values = ContentValues().apply {
put(MediaStore.Video.Media.TITLE, fileToCreate.name)
put(MediaStore.Video.Media.MIME_TYPE, "video/mp4")
put(MediaStore.Video.Media.DATA, fileToCreate.path)
}
context.contentResolver.insert(MediaStore.Video.Media.EXTERNAL_CONTENT_URI, values)
}
} catch (e: IOException) {
e.printStackTrace()
}
return null
}
private val TEMPORARY_DIR_Q = Environment.DIRECTORY_MOVIES + File.separator +
"APPNAME" + File.separator +
"temporary" + File.separator
private val TEMPORARY_DIR_BELOWQ = Environment.getExternalStoragePublicDirectory(
Environment.DIRECTORY_MOVIES).absolutePath + File.separator +
"APPNAME" + File.separator +
"temporary" + File.separator
I am trying to sync room database with google drive and I have followed this document https://medium.com/glucosio-project/backup-restore-a-realm-database-on-google-drive-with-drive-api-c238515a5975 but I can't sync database in the drive.
I also tried to https://stackoverflow.com/a/49297966/8143436 this answer and also,try to sync database like below :
I have tried below:
private fun singIn() {
val requiredScopes = HashSet<Scope>(2)
requiredScopes.add(Drive.SCOPE_FILE)
val signInAccount = GoogleSignIn.getLastSignedInAccount(activity!!)
if (signInAccount != null && signInAccount.grantedScopes.containsAll(requiredScopes)) {
initializeDriveClient(signInAccount)
} else {
val signInOptions = GoogleSignInOptions.Builder(GoogleSignInOptions.DEFAULT_SIGN_IN)
.requestScopes(Drive.SCOPE_FILE)
.build()
val googleSignInClient = GoogleSignIn.getClient(activity!!, signInOptions)
startActivityForResult(googleSignInClient.signInIntent, REQUEST_CODE_SIGN_IN)
}
}
private fun initializeDriveClient(signInAccount: GoogleSignInAccount) {
driveClient = Drive.getDriveClient(activity!!, signInAccount)
driveResourceClient = Drive.getDriveResourceClient(activity!!, signInAccount)
onDriveClientReady()
}
private fun onDriveClientReady() {
getRootFolder()
}
private fun getRootFolder() {
/* Get the app folder */
val appFolderTask = driveResourceClient!!.rootFolder
appFolderTask.addOnSuccessListener {
baseFolder = it
checkForBackUp()
}
appFolderTask.addOnFailureListener {
}
}
private fun checkForBackUp() {
val query = Query.Builder()
.addFilter(Filters.eq(SearchableField.TITLE, BACK_UP))
.build()
val queryTask = baseFolder?.let { driveResourceClient?.queryChildren(it, query) }
queryTask!!.addOnSuccessListener(activity!!, object : OnSuccessListener<MetadataBuffer> {
override fun onSuccess(metadataBuffer: MetadataBuffer?) {
if (metadataBuffer?.count == 0) {
Log.d("TTTT", "File $BACK_UP not found\n")
/* Make file backup */
backUpDatabase()
} else {
Log.d("TTTT", metadataBuffer?.count.toString() + " Instances of file " + BACK_UP + " found\n")
val metadata = metadataBuffer?.get(metadataBuffer.count - 1)
restoreBackUp(metadata?.driveId!!.asDriveFile())
}
}
})
}
private fun restoreBackUp(asDriveFile: DriveFile?) {
// if (!dbShm.exists()) {
// Log.d("Hello", "Local database not found?!\\n")
// return
// }
val dbFileOld = activity!!.getDatabasePath("my_db")
/* Check of dbFileExists on device, delete if it does because it needs to be completely over written */
if (dbFileOld.exists()) {
dbFileOld.delete()
}
val dbFileNew = activity!!.getDatabasePath("my_db")
val fileOutputStream = FileOutputStream(dbFileNew)
val openFileTask = driveResourceClient?.openFile(asDriveFile!!, DriveFile.MODE_READ_ONLY);
openFileTask?.continueWith { p0 ->
val backupContents = p0.result
val inputStream = backupContents!!.inputStream
Log.d("TTTT", "Attempting to restore from database\n")
val buffer = ByteArray(1024)
var c: Int = inputStream.read(buffer, 0, buffer.size)
while (c != -1 && c > 0) {
fileOutputStream.write(buffer, 0, c)
c = inputStream.read(buffer, 0, buffer.size)
}
fileOutputStream.flush()
fileOutputStream.close()
fileOutputStream.flush()
fileOutputStream.close()
Log.d("TTTT", "Database restored\n")
driveResourceClient!!.discardContents(backupContents)
}?.addOnFailureListener {
Log.d("TTTT", "Could not read file contents\\n")
}
}
private fun backUpDatabase() {
val db = activity!!.getDatabasePath("my_db")
if (!db.exists()) {
Log.d("TTTT", "Local database not found?!\\n")
return
}
val fileInputStream = FileInputStream(db)
val createContentsTask = driveResourceClient?.createContents()
Log.d("TTTT", "Creating a back-up of the Database File\n")
Tasks.whenAll(createContentsTask).continueWithTask {
val contents = createContentsTask?.result
val outputStream = contents?.outputStream
Log.d("TTTT", "Attempting to write\\n")
val buffer = ByteArray(1024)
var c: Int = fileInputStream.read(buffer)
while (c != -1) {
outputStream?.write(buffer, 0, c)
c = fileInputStream.read(buffer)
}
outputStream!!.flush()
outputStream.close()
fileInputStream.close()
Log.d("TTTT", "Database written\\n")
val changeSet = MetadataChangeSet.Builder()
.setTitle(BACK_UP)
.setMimeType("application/x-sqlite3")
.setStarred(false)
.build()
driveResourceClient!!.createFile(baseFolder!!, changeSet, contents)
}.addOnSuccessListener {
Log.d("TTTT", "Back up file created\n")
}.addOnFailureListener {
Log.d("TTTT", "Could not create back up file\n")
}
}
is this possible to sync the room database in google drive?