I want to fetch Google photos and show into app. I used below code but it is not working.
try {
val credentialsStream : InputStream = resources.openRawResource(R.raw.credential)
val credentials: GoogleCredentials =
GoogleCredentials.fromStream(credentialsStream)
.createScoped(Collections.singletonList("https://www.googleapis.com/auth/photoslibrary.readonly"))
val settings = PhotosLibrarySettings.newBuilder()
.setCredentialsProvider(FixedCredentialsProvider.create(credentials))
.build()
val photosLibraryClient: PhotosLibraryClient = PhotosLibraryClient.initialize(settings)
val albums: MutableIterable<Album>? = photosLibraryClient.listAlbums().iterateAll()
if (albums != null) {
for (album in albums) {
println("Album title: " + album.title)
println("Album product URL: " + album.productUrl)
}
}
} catch (e: ApiException) {
JLog.w("Error", "handleSignInResult:error: ${e.message}")
e.printStackTrace()
}
I used below libs
implementation ('io.grpc:grpc-okhttp:1.31.1') {
exclude group: "com.squareup.okhttp"
}
implementation 'com.google.api-client:google-api-client-android:1.31.1'
implementation 'com.google.photos.library:google-photos-library-client:1.7.2'
implementation 'com.google.auth:google-auth-library-oauth2-http:1.7.0'
But when i try to this i got java.lang.NoSuchMethodError: No direct method (Ljava/lang/String;)V in class Lio/grpc/internal/AbstractManagedChannelImplBuilder; or its super classes (declaration of 'io.grpc.internal.AbstractManagedChannelImplBuilder' appears in /data/app/~~MOmfPzH0_A99g7RxMbRc7Q==/com.clicandprint-OwkMyEC4oLeBuyKNeMogtw==/base.apk!classes33.dex)
error on this line
val photosLibraryClient: PhotosLibraryClient = PhotosLibraryClient.initialize(settings)
Related
I'm trying to upload a JPEG to MongoDB using Ktor and Kotlin but keep getting an error:
java.io.FileNotFoundException: /document/image:32: open failed: ENOENT (No such file or directory)
Please help if someone knows what I am doing wrong here
It is a strange error, because I'm sure that uri is ok. I can display an image in app with this.
First things first:
KTOR SIDE:
fun Route.uploadFile(
app: Application){
val client = KMongo.createClient()
val database = client.getDatabase(IMAGES_DATABASE_NAME)
val bucket = GridFSBuckets.create(database, "images")
post("/upload_photo") {
try {
val multipartData = call.receiveMultipart()
multipartData.forEachPart { part ->
if (part is PartData.FileItem) {
val fileName = part.originalFileName as String
withContext(Dispatchers.IO) {
bucket.uploadFromStream(fileName, part.streamProvider())
}
call.respond(
message = ApiResponse(
success = true,
message = ""
)
)
} else {
call.respond(
message = ApiResponse(
success = false,
message = ""
)
)
}
}
} catch (e: Exception) {
app.log.info("Error: ${e.message}")
call.respond(
message = ApiResponse(
message = "Error: ${e.message}",
success = false
),
status = HttpStatusCode.BadRequest
)
}
}
API INTERFACE:
#Multipart
#POST("/upload_photo")
suspend fun uploadPhoto(
#Part filePart: MultipartBody.Part
):ApiResponse
Now, I suppose that the problem occures on kotlin Android App side:
Function where the problem occures:
override suspend fun uploadFile(photo: Uri): ApiResponse {
return try {
val file = photo.path?.let { File(it) }
val requestBody = file!!.asRequestBody()
val body = MultipartBody.Part.createFormData("photo",file.name, requestBody )
Log.d("Upload", body.toString())
ktorApi.uploadPhoto(body)
} catch (e: Exception) {
Log.d("Upload: ", "{ $e.message }")
ApiResponse(
success = false,
error = e
)
}
}
I found a solution to my problem.
To make a post with Uri possible is it necessary to create a temporary file in local cashe. For example with the method like thise:
private fun createFileFromUri(name: String, uri: Uri, context: Context): File? {
return try {
val stream = context.contentResolver.openInputStream(uri)
val file =
File.createTempFile(
"${name}_${System.currentTimeMillis()}",
".jpg",
context.cacheDir
)
FileUtils.copyInputStreamToFile(stream, file) // Use this one import org.apache.commons.io.FileUtils
file
} catch (e: Exception) {
e.printStackTrace()
null
}
}
and a dependency in gradle :
implementation group: 'commons-io', name: 'commons-io', version: '2.7'
implementation group: 'org.apache.commons', name: 'commons-text', version: '1.9'
I am stuck in between a strange issue of uploading image file to server. Although I did upload file several times before, but this time I don't understand what is the issue.
I get the file path of respective file but RequestBody returns null. Below I mentioned what library I'm using.
I am using kotlin, MultiPart and RequestBody for file upload.
implementation 'com.squareup.retrofit2:retrofit:2.9.0'
implementation 'com.squareup.retrofit2:converter-gson:2.9.0'
implementation 'com.squareup.okhttp3:logging-interceptor:4.9.1'
Below is my code which I wrote for file upload. In which you can see GalleryCameraUtility.getImageRequestBody(imageFile) returns null for file.
File path from mobile device /storage/emulated/0/DCIM/Screenshots/test_image.jpg
fun addNewCompany(companyName: String, email: String,imageFile: File, ownerName: String, address: String, companyDetails: String){
val companyNameBody: RequestBody = companyName.toRequestBody("text/plain".toMediaType())
val emailBody: RequestBody = email.toRequestBody("text/plain".toMediaType())
val fileData: RequestBody? = GalleryCameraUtility.getImageRequestBody(imageFile)
val ownerNameBody: RequestBody = ownerName.toRequestBody("text/plain".toMediaType())
val addressBody: RequestBody = address.toRequestBody("text/plain".toMediaType())
val userIdBody: RequestBody = PreferenceHelper.readUserIdPref(Constants.USER_ID).toString()
.toRequestBody("text/plain".toMediaType())
addCompanyRepo.addNewCompanyApi(companyNameBody, emailBody, fileData, ownerNameBody, addressBody, userIdBody)
}
class GalleryCameraUtility {
companion object{
fun getImageRequestBody(sourceFile: File) : RequestBody? {
var requestBody: RequestBody? = null
Thread {
val mimeType = getMimeType(sourceFile);
if (mimeType == null) {
Log.e("file error", "Not able to get mime type")
return#Thread
}
try {
requestBody = sourceFile.path.toRequestBody("multipart/form-data".toMediaTypeOrNull())
/*MultipartBody.Builder().setType(MultipartBody.FORM)
.addFormDataPart(serverImageKey, uploadedFileName,sourceFile.asRequestBody(mimeType.toMediaTypeOrNull()))
.build()*/
} catch (ex: Exception) {
ex.printStackTrace()
Log.e("File upload", "failed")
}
}.start()
return requestBody;
}
// url = file path or whatever suitable URL you want.
private fun getMimeType(file: File): String? {
var type: String? = null
val extension = MimeTypeMap.getFileExtensionFromUrl(file.path)
if (extension != null) {
type = MimeTypeMap.getSingleton().getMimeTypeFromExtension(extension)
}
return type
}
}
}
I spent so many hours on this but not able to find solution. Please help me out on this.
While upload my app in Google playstore I get this error; We've detected this app uses an unsupported version of Play billing. Please upgrade to Billing Library version 3 or newer to publish this app.
Below are the dependencies on my android studio app, which of them is the billing library to change?
implementation fileTree(dir: 'libs', include: ['*.jar'])
implementation 'com.google.android.material:material:1.1.0'
implementation 'com.github.AnchorFreePartner.hydra-sdk-android:sdk:3.1.1'
implementation 'com.github.AnchorFreePartner.hydra-sdk-android:openvpn:3.1.1'
implementation 'junit:junit:4.12'
implementation 'androidx.appcompat:appcompat:1.1.0'
implementation 'androidx.cardview:cardview:1.0.0'
implementation 'androidx.recyclerview:recyclerview:1.1.0'
implementation 'com.android.support:multidex:1.0.3'
implementation 'com.jakewharton:butterknife:10.1.0'
implementation 'androidx.constraintlayout:constraintlayout:1.1.3'
annotationProcessor 'com.jakewharton:butterknife-compiler:10.2.1'
implementation 'com.google.android.gms:play-services-ads:19.0.1'
implementation 'com.facebook.android:audience-network-sdk:5.6.1'
implementation 'com.onesignal:OneSignal:3.12.7#aar'
implementation 'com.google.firebase:firebase-analytics:17.3.0'
implementation 'com.google.android.gms:play-services-gcm:17.0.0'
implementation 'com.google.android.gms:play-services-location:17.0.0'
implementation 'com.anjlab.android.iab.v3:library:1.1.0'
implementation 'com.squareup.retrofit2:retrofit:2.6.2'
implementation 'com.google.code.gson:gson:2.8.5'
implementation 'com.squareup.retrofit2:converter-gson:2.6.2'
You are using this library for InApp purchasing but this library says we have updated to V3 but Google play store warn about this library that library is not updated to V3 or V4
implementation 'com.anjlab.android.iab.v3:library:1.1.0'
You should use Official documents for InApp Purchasing
Example V4
build.gradle
implementation 'com.android.billingclient:billing:4.0.0'
strings.xml
<string name="license_key">Place Your ID Here</string>
<string name="product_id">android.test.purchased</string>
InAppPurchase.kt
import android.app.Activity
import android.content.Context
import android.widget.Toast
import com.android.billingclient.api.*
import java.io.IOException
import java.util.ArrayList
class InAppPurchase(context: Context) : PurchasesUpdatedListener{
private val mContext: Context = context
private var billingClient: BillingClient
var ackPurchase =
AcknowledgePurchaseResponseListener { billingResult ->
if (billingResult.responseCode == BillingClient.BillingResponseCode.OK) {
//if purchase is acknowledged
// Grant entitlement to the user. and restart activity
SharedPreferencesUtils.setPurchasedBillingValue(mContext, true)
showMessage("Item Purchased")
(mContext as Activity).recreate()
}
}
init {
billingClient =
BillingClient.newBuilder(mContext).enablePendingPurchases().setListener(this).build()
billingClient.startConnection(object : BillingClientStateListener {
override fun onBillingSetupFinished(billingResult: BillingResult) {
if (billingResult.responseCode == BillingClient.BillingResponseCode.OK) {
val queryPurchase = billingClient.queryPurchases(BillingClient.SkuType.INAPP)
val queryPurchases = queryPurchase.purchasesList
if (queryPurchases != null && queryPurchases.size > 0) {
handlePurchases(queryPurchases)
} else {
SharedPreferencesUtils.setPurchasedBillingValue(mContext, false)
}
}
}
override fun onBillingServiceDisconnected() {}
})
}
fun productPurchase() {
//check if service is already connected
if (billingClient.isReady) {
initiatePurchase()
} else {
billingClient =
BillingClient.newBuilder(mContext).enablePendingPurchases().setListener(this).build()
billingClient.startConnection(object : BillingClientStateListener {
override fun onBillingSetupFinished(billingResult: BillingResult) {
if (billingResult.responseCode == BillingClient.BillingResponseCode.OK) {
initiatePurchase()
} else {
showMessage("Error" + billingResult.debugMessage)
}
}
override fun onBillingServiceDisconnected() {}
})
}
}
private fun initiatePurchase() {
val skuList: MutableList<String> = ArrayList()
skuList.add(mContext.resources.getString(R.string.product_id))
val params = SkuDetailsParams.newBuilder()
params.setSkusList(skuList).setType(BillingClient.SkuType.INAPP)
billingClient.querySkuDetailsAsync(
params.build()
) { billingResult, skuDetailsList ->
if (billingResult.responseCode == BillingClient.BillingResponseCode.OK) {
if (skuDetailsList != null && skuDetailsList.size > 0) {
val flowParams = BillingFlowParams.newBuilder()
.setSkuDetails(skuDetailsList[0])
.build()
billingClient.launchBillingFlow(mContext as Activity, flowParams)
} else {
//try to add item/product id "purchase" inside managed product in google play console
showMessage("Purchase Item not Found")
}
} else {
showMessage(" Error " + billingResult.debugMessage)
}
}
}
/**
* Verifies that the purchase was signed correctly for this developer's public key.
*
* Note: It's strongly recommended to perform such check on your backend since hackers can
* replace this method with "constant true" if they decompile/rebuild your app.
*
*/
private fun verifyValidSignature(signedData: String, signature: String): Boolean {
return try {
// To get key go to Developer Console > Select your app > Development Tools > Services & APIs.
val base64Key = mContext.getString(R.string.license_key)
Security.verifyPurchase(base64Key, signedData, signature)
} catch (e: IOException) {
false
}
}
fun handlePurchases(purchases: List<Purchase>) {
for (purchase in purchases) {
//if item is purchased
if (mContext.getString(R.string.product_id) == purchase.skus[0] && purchase.purchaseState == Purchase.PurchaseState.PURCHASED) {
if (!verifyValidSignature(purchase.originalJson, purchase.signature)) {
// Invalid purchase
// show error to user
showMessage("Invalid Purchase")
return
}
// else purchase is valid
// if item is purchased and not acknowledged
if (!purchase.isAcknowledged) {
val acknowledgePurchaseParams = AcknowledgePurchaseParams.newBuilder()
.setPurchaseToken(purchase.purchaseToken)
.build()
billingClient.acknowledgePurchase(acknowledgePurchaseParams, ackPurchase)
} else {
// Grant entitlement to the user on item purchase
// restart activity
if (!SharedPreferencesUtils.getPurchasedBillingValue(mContext)) {
SharedPreferencesUtils.setPurchasedBillingValue(mContext,true)
showMessage("Item Purchased")
(mContext as Activity).recreate()
}
}
} else if (mContext.getString(R.string.product_id) == purchase.skus[0] && purchase.purchaseState == Purchase.PurchaseState.PENDING) {
showMessage("Purchase is Pending. Please complete Transaction")
} else if (mContext.getString(R.string.product_id) == purchase.skus[0] && purchase.purchaseState == Purchase.PurchaseState.UNSPECIFIED_STATE) {
SharedPreferencesUtils.setPurchasedBillingValue(mContext,false)
showMessage("Purchase Status Unknown")
}
}
}
private fun showMessage(message: String) {
(mContext as Activity).runOnUiThread{
Toast.makeText(mContext, message, Toast.LENGTH_SHORT).show()
}
}
override fun onPurchasesUpdated(billingResult: BillingResult, purchases: MutableList<Purchase>?) {
//if item newly purchased
if (billingResult.responseCode == BillingClient.BillingResponseCode.OK && purchases != null) {
handlePurchases(purchases)
} else if (billingResult.responseCode == BillingClient.BillingResponseCode.ITEM_ALREADY_OWNED) {
val queryAlreadyPurchasesResult =
billingClient.queryPurchases(BillingClient.SkuType.INAPP)
val alreadyPurchases = queryAlreadyPurchasesResult.purchasesList
alreadyPurchases?.let { handlePurchases(it) }
} else if (billingResult.responseCode == BillingClient.BillingResponseCode.USER_CANCELED) {
showMessage("Purchase Canceled")
} else {
showMessage("Error updated" + billingResult.debugMessage)
}
}
fun onDestroyBilling() {
billingClient.endConnection()
}
}
Security.kt
import android.text.TextUtils
import android.util.Base64
import java.io.IOException
import java.security.*
import java.security.spec.InvalidKeySpecException
import java.security.spec.X509EncodedKeySpec
/**
* Security-related methods. For a secure implementation, all of this code should be implemented on
* a server that communicates with the application on the device.
*/
object Security {
private const val KEY_FACTORY_ALGORITHM = "RSA"
private const val SIGNATURE_ALGORITHM = "SHA1withRSA"
/**
* Verifies that the data was signed with the given signature, and returns the verified
* purchase.
* #param base64PublicKey the base64-encoded public key to use for verifying.
* #param signedData the signed JSON string (signed, not encrypted)
* #param signature the signature for the data, signed with the private key
* #throws IOException if encoding algorithm is not supported or key specification
* is invalid
*/
#Throws(IOException::class)
fun verifyPurchase(
base64PublicKey: String, signedData: String,
signature: String
): Boolean {
if (TextUtils.isEmpty(signedData) || TextUtils.isEmpty(base64PublicKey)
|| TextUtils.isEmpty(signature)
) {
//Purchase verification failed: missing data
return false
}
val key = generatePublicKey(base64PublicKey)
return verify(key, signedData, signature)
}
/**
* Generates a PublicKey instance from a string containing the Base64-encoded public key.
*
* #param encodedPublicKey Base64-encoded public key
* #throws IOException if encoding algorithm is not supported or key specification
* is invalid
*/
#Throws(IOException::class)
fun generatePublicKey(encodedPublicKey: String): PublicKey {
return try {
val decodedKey = Base64.decode(encodedPublicKey, Base64.DEFAULT)
val keyFactory = KeyFactory.getInstance(KEY_FACTORY_ALGORITHM)
keyFactory.generatePublic(X509EncodedKeySpec(decodedKey))
} catch (e: NoSuchAlgorithmException) {
// "RSA" is guaranteed to be available.
throw RuntimeException(e)
} catch (e: InvalidKeySpecException) {
val msg = "Invalid key specification: $e"
throw IOException(msg)
}
}
/**
* Verifies that the signature from the server matches the computed signature on the data.
* Returns true if the data is correctly signed.
*
* #param publicKey public key associated with the developer account
* #param signedData signed data from server
* #param signature server signature
* #return true if the data and signature match
*/
private fun verify(publicKey: PublicKey, signedData: String, signature: String): Boolean {
val signatureBytes: ByteArray = try {
Base64.decode(signature, Base64.DEFAULT)
} catch (e: IllegalArgumentException) {
//Base64 decoding failed
return false
}
try {
val signatureAlgorithm = Signature.getInstance(SIGNATURE_ALGORITHM)
signatureAlgorithm.initVerify(publicKey)
signatureAlgorithm.update(signedData.toByteArray())
return signatureAlgorithm.verify(signatureBytes)
} catch (e: NoSuchAlgorithmException) {
// "RSA" is guaranteed to be available
throw RuntimeException(e)
} catch (e: InvalidKeyException) {
//Invalid key specification
} catch (e: SignatureException) {
//Signature exception
}
return false
}
}
MainActivity.kt
var inAppPurchase: InAppPurchase = InAppPurchase(this)
btnInApp.setOnClickListener {
inAppPurchase.productPurchase()
}
exception: Token is invalid or expired.
What is this error? I have already set the api key. And what does this token represent?
val setting: MLRemoteTranslateSetting =
MLRemoteTranslateSetting.Factory()
.setSourceLangCode("en")
.setTargetLangCode("hu")
.create()
val mlRemoteTranslator: MLRemoteTranslator =
MLTranslatorFactory.getInstance().getRemoteTranslator(setting)
try {
val result = MLTranslateLanguage.syncGetCloudAllLanguages()
} catch (e: MLException) {
Log.e("ML exception", e.message.toString())
}
var output = ""
try {
output = mlRemoteTranslator.syncTranslate("SOURCE")
} catch (e: MLException) {
Log.e("ML exception", e.message.toString())
}
mlRemoteTranslator.stop()
I get this error here: val result = MLTranslateLanguage.syncGetCloudAllLanguages()
and here: output = mlRemoteTranslator.syncTranslate("SOURCE")
I set the api key like this: MLApplication.getInstance().apiKey = Utils.apiKey
object Utils {
private const val TAG = "Utils"
#JvmStatic
val apiKey: String?
get() {
// get apiKey from AppGallery Connect
val apiKey = "myApiKey"
// need encodeURI the apiKey
return try {
URLEncoder.encode(apiKey, "utf-8")
} catch (e: UnsupportedEncodingException) {
Log.e(TAG, "encode apikey error")
null
}
}}
I'm trying to upload a file to Google Drive using Google Drive REST API v3. After the upload process is completed, it returns a status code of 200 (successful). But I can't find the files in my Google Drive. Please tell me what am I doing wrong? I will really appreciate if you provide a proper illustration or better still code snippet while helping me with this problem of mine. I am really anticipating your answers.
I have tried following the documentation but I am still getting the same error. I have searched everywhere online and stackoverflow, but none seems to provide the solution to my problem.
here is the code
private val AUTHORIZATION_PARAM = "Authorization"
private val BEARER_VAL = "Bearer "
private val CONTENT_TYPE_PARAM = "Content-Type: "
private val LINE_FEED = "\r\n"
private val APP_FOLDER_ID = "appDataFolder"
fun connectAndStartOperation() {
if (mAuthCode == null) {
signInOptions = GoogleSignInOptions.Builder(GoogleSignInOptions.DEFAULT_SIGN_IN)
.requestEmail()
.requestProfile()
.requestScopes(Scope(Scopes.DRIVE_APPFOLDER))
.requestIdToken(resources.getString(R.string.gdrive_clientId))
.requestServerAuthCode(resources.getString(R.string.gdrive_clientId))
.build()
mGoogleSignInClient = GoogleSignIn.getClient(this, signInOptions!!)
startActivityForResult(mGoogleSignInClient?.signInIntent, CLOUD_STORAGE)
Log.i("mAuthCode", "false")
} else {
Log.i("mAuthCode", "true")
writeDbToDrive()
mNextGoogleApiOperation = INVALID;
}
}
fun disconnect() {
mGoogleSignInClient?.signOut()
mActivity = null
mNextGoogleApiOperation = INVALID
mAuthCode = null
mAccessToken = null
mTokenExpired = 0
}
override fun onDestroy() {
disconnect()
super.onDestroy()
}
public override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
if (requestCode == CLOUD_STORAGE) {
val task = GoogleSignIn.getSignedInAccountFromIntent(data)
.addOnSuccessListener(this)
.addOnFailureListener(this)
}
}
override fun onSuccess(googleSignInAccount: GoogleSignInAccount?) {
Log.i("mAuthCode", "Success")
val scope = "oauth2:https://www.googleapis.com/auth/plus.me https://www.googleapis.com/auth/userinfo.profile"
idTokenString = googleSignInAccount?.idToken
mAuthCode = googleSignInAccount?.serverAuthCode
mGoogleSignInAccount = googleSignInAccount
doAsync {
try {
mAccessToken = GoogleAuthUtil.getToken(this#SettingsActivity, mGoogleSignInAccount?.account, scope)
} catch (e: Exception) {
Log.i("Error AccessToken", "${e.message}")
e.printStackTrace()
}
uiThread {
Log.i("AccessTokenMy", "$mAccessToken")
}
}
}
override fun onFailure(p0: java.lang.Exception) {
Log.i("mAuthCode", "Failed")
p0.printStackTrace()
}
private fun writeDbToDrive() {
var conn: HttpURLConnection? = null
var os: OutputStream? = null
val accessToken = requestAccessToken(mGoogleSignInAccount!!)
if (accessToken == null)
return
try {
val boundary = "pb" + System.currentTimeMillis()
val url = URL("https://www.googleapis.com/upload/drive/v3/files?uploadType=multipart")
conn = url.openConnection() as HttpURLConnection
conn.requestMethod = "POST"
conn.useCaches = false
conn.doOutput = true
conn.doInput = true
conn.connectTimeout = 5000
conn.setRequestProperty(AUTHORIZATION_PARAM, BEARER_VAL + accessToken!!)
conn.setRequestProperty("Content-Type", "multipart/related; boundary=$boundary")
Log.i("Action", "Parameter set for server")
/////// Prepare data
//val timestamp = SimpleDateFormat("yyyy-MM-dd_HH:mm:ss", Locale.getDefault()).format(Date())
// Prepare file metadata (Change your backup file name here)
val b = StringBuilder()
b.append('{')
.append("\"name\":\"").append(exportedFileName).append('\"')
.append(',')
.append("\"mimeType\":").append("\"text\\/csv\"")
.append(',') //"\"application\\/vnd.google-apps.unknown\""
.append("\"parents\":").append("[\"").append(APP_FOLDER_ID).append("\"]")
.append('}')
val metadata = b.toString()
val data = readFile(File(filePath))
/////// Calculate body length
var bodyLength = 0
// MetaData part
b.setLength(0)
b.append("--").append(boundary).append(LINE_FEED)
b.append(CONTENT_TYPE_PARAM).append("application/json; charset=UTF-8")
.append(LINE_FEED)
b.append(LINE_FEED)
b.append(metadata).append(LINE_FEED)
b.append(LINE_FEED)
b.append("--").append(boundary).append(LINE_FEED)
b.append(CONTENT_TYPE_PARAM).append("text/csv").append(LINE_FEED)
b.append(LINE_FEED)
val beforeFilePart = b.toString().toByteArray(charset("UTF_8"))
bodyLength += beforeFilePart.size
bodyLength += data.size // File
b.setLength(0)
b.append(LINE_FEED)
b.append("--").append(boundary).append("--")
val afterFilePart = b.toString().toByteArray(charset("UTF_8"))
bodyLength += afterFilePart.size
conn.setRequestProperty("Content-Length", bodyLength.toString())
//if (BuildConfig.DEBUG_MODE) DebugHelper.log("LENGTH", bodyLength)
/////// Write to socket
os = conn.outputStream
try {
os!!.write(beforeFilePart)
os!!.write(data)
os!!.write(afterFilePart)
os!!.flush()
} catch (e: Exception) {
e.printStackTrace()
}
val msg = conn.responseMessage
val code = conn.responseCode
if (code == 200) {
Log.i("writeDbToDrive", "Exported Successfully: $code $msg")
} else {
Log.i("writeDbToDrive", "Error: $code $msg")
}
} catch (e: Exception) {
e.printStackTrace()
Log.i("writeDbToDrive", e.message!!)
} finally {
if (os != null) {
try {
os!!.close()
} catch (e: IOException) {
}
}
conn?.disconnect()
}
}
#Throws(IOException::class)
private fun readFile(file: File): ByteArray {
val f = RandomAccessFile(file, "r")
try {
val longlength = f.length()
val length = longlength.toInt()
if (length.toLong() != longlength)
throw IOException("File size >= 10 Mb")
val data = ByteArray(length)
f.readFully(data)
return data
} finally {
f.close()
}
}
private fun requestAccessToken(mGoogleSignInAccount: GoogleSignInAccount): String? {
val scope = "oauth2:https://www.googleapis.com/auth/plus.me https://www.googleapis.com/auth/userinfo.profile"
doAsync {
try {
mAccessToken = GoogleAuthUtil.getToken(this#SettingsActivity, mGoogleSignInAccount?.account, scope)
} catch (e: Exception) {
Log.i("Error AccessToken", "${e.message}")
e.printStackTrace()
}
uiThread {
Log.i("AccessTokenMy", "$mAccessToken")
}
}
return mAccessToken
}
After reading through this Files: create Documentation, I have finally fixed the problem. Unknown to me is that the files where being saved in the AppData folder created by my app. The AppData folder is hidden which can only be accessible by and through my app. For me to be able to save the file to My Drive folder, I removed the part of the metadata
` .append(',')
.append("\"parents\":").append("[\"").append(APP_FOLDER_ID).append("\"]")`
So the metadata part is now like this
val b = StringBuilder()
b.append('{')
.append("\"name\":\"").append(exportedFileName).append('\"')
.append(',')
.append("\"mimeType\":").append("\"text\\/csv\"")
.append('}')
val metadata = b.toString()
Every other thing remains the same