using drive web api

This commit is contained in:
Mariotaku Lee 2017-01-20 16:25:03 +08:00
parent f8c65e0269
commit fe72d897be
No known key found for this signature in database
GPG Key ID: 9C0706AE47FCE2AD
5 changed files with 74 additions and 107 deletions

View File

@ -98,12 +98,12 @@ dependencies {
// START Non-FOSS component
googleCompile "com.google.android.gms:play-services-maps:$play_services_version"
googleCompile "com.google.android.gms:play-services-auth:$play_services_version"
googleCompile "com.google.android.gms:play-services-drive:$play_services_version"
googleCompile 'com.google.maps.android:android-maps-utils:0.4.4'
googleCompile('com.crashlytics.sdk.android:crashlytics:2.6.5@aar') { transitive = true }
googleCompile 'com.anjlab.android.iab.v3:library:1.0.38'
googleCompile 'com.dropbox.core:dropbox-core-sdk:2.1.2'
googleCompile ':YouTubeAndroidPlayerApi:1.2.2@jar'
googleCompile 'com.google.apis:google-api-services-drive:v3-rev55-1.22.0'
// END Non-FOSS component
fdroidCompile 'org.osmdroid:osmdroid-android:5.5:release@aar'

View File

@ -1,79 +1,67 @@
package org.mariotaku.twidere.activity.sync
import android.accounts.Account
import android.accounts.AccountManager
import android.app.Activity
import android.content.Intent
import android.content.IntentSender
import android.os.Bundle
import com.google.android.gms.common.ConnectionResult
import com.google.android.gms.common.GooglePlayServicesUtil
import com.google.android.gms.common.api.GoogleApiClient
import com.google.android.gms.drive.Drive
import com.google.android.gms.auth.GoogleAuthUtil
import com.google.android.gms.auth.UserRecoverableAuthException
import com.google.android.gms.common.AccountPicker
import com.google.api.services.drive.DriveScopes
import nl.komponents.kovenant.task
import nl.komponents.kovenant.ui.successUi
import org.mariotaku.kpreferences.set
import org.mariotaku.twidere.activity.BaseActivity
import org.mariotaku.twidere.constant.dataSyncProviderInfoKey
import org.mariotaku.twidere.model.sync.GoogleDriveSyncProviderInfo
class GoogleDriveAuthActivity : BaseActivity(), GoogleApiClient.ConnectionCallbacks,
GoogleApiClient.OnConnectionFailedListener {
private lateinit var googleApiClient: GoogleApiClient
class GoogleDriveAuthActivity : BaseActivity() {
public override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
googleApiClient = GoogleApiClient.Builder(this)
.addApi(Drive.API)
.addScope(Drive.SCOPE_APPFOLDER)
.addConnectionCallbacks(this)
.addOnConnectionFailedListener(this)
.build()
val intent = AccountPicker.newChooseAccountIntent(null, null,
arrayOf(GoogleAuthUtil.GOOGLE_ACCOUNT_TYPE), false, null, null, null, null)
startActivityForResult(intent, REQUEST_CODE_CHOOSE_ACCOUNT)
}
override fun onStart() {
super.onStart()
googleApiClient.connect()
}
override fun onStop() {
googleApiClient.disconnect()
super.onStop()
}
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent) {
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
when (requestCode) {
RESOLVE_CONNECTION_REQUEST_CODE -> if (resultCode == Activity.RESULT_OK) {
googleApiClient.connect()
REQUEST_CODE_CHOOSE_ACCOUNT -> {
if (resultCode == Activity.RESULT_OK && data != null) {
val name = data.getStringExtra(AccountManager.KEY_ACCOUNT_NAME)
val type = data.getStringExtra(AccountManager.KEY_ACCOUNT_TYPE)
val account = Account(name, type)
task {
return@task GoogleAuthUtil.getToken(this, account, "oauth2:${DriveScopes.DRIVE_APPDATA}")
}.successUi { accessToken ->
preferences[dataSyncProviderInfoKey] = GoogleDriveSyncProviderInfo(accessToken)
finish()
}.fail { ex ->
if (ex is UserRecoverableAuthException) {
startActivityForResult(ex.intent, REQUEST_CODE_AUTH_ERROR_RECOVER)
} else {
finish()
}
}
}
}
}
}
override fun onConnectionFailed(connectionResult: ConnectionResult) {
if (connectionResult.hasResolution()) {
try {
connectionResult.startResolutionForResult(this, RESOLVE_CONNECTION_REQUEST_CODE)
} catch (e: IntentSender.SendIntentException) {
// Unable to resolve, message user appropriately
}
} else {
preferences[dataSyncProviderInfoKey] = null
GooglePlayServicesUtil.showErrorDialogFragment(connectionResult.errorCode, this, null, 0) {
REQUEST_CODE_AUTH_ERROR_RECOVER -> {
if (resultCode == Activity.RESULT_OK && data != null) {
val name = data.getStringExtra(AccountManager.KEY_ACCOUNT_NAME)
val type = data.getStringExtra(AccountManager.KEY_ACCOUNT_TYPE)
val token = data.getStringExtra(AccountManager.KEY_AUTHTOKEN)
preferences[dataSyncProviderInfoKey] = GoogleDriveSyncProviderInfo(token)
}
finish()
}
}
}
override fun onConnected(connectionHint: Bundle?) {
preferences[dataSyncProviderInfoKey] = GoogleDriveSyncProviderInfo()
finish()
}
override fun onConnectionSuspended(cause: Int) {
finish()
}
companion object {
private const val RESOLVE_CONNECTION_REQUEST_CODE: Int = 101
private const val REQUEST_CODE_CHOOSE_ACCOUNT: Int = 101
private const val REQUEST_CODE_AUTH_ERROR_RECOVER: Int = 102
}
}

View File

@ -5,20 +5,22 @@ import android.content.SharedPreferences
import org.mariotaku.twidere.util.sync.SyncTaskRunner
import org.mariotaku.twidere.util.sync.google.GoogleDriveSyncTaskRunner
class GoogleDriveSyncProviderInfo : SyncProviderInfo(GoogleDriveSyncProviderInfo.TYPE) {
class GoogleDriveSyncProviderInfo(val accessToken: String) : SyncProviderInfo(GoogleDriveSyncProviderInfo.TYPE) {
override fun writeToPreferences(editor: SharedPreferences.Editor) {
editor.putString(KEY_GOOGLE_DRIVE_AUTH_TOKEN, accessToken)
}
override fun newSyncTaskRunner(context: Context): SyncTaskRunner {
return GoogleDriveSyncTaskRunner(context)
return GoogleDriveSyncTaskRunner(context, accessToken)
}
companion object {
const val TYPE = "google_drive"
private const val KEY_GOOGLE_DRIVE_AUTH_TOKEN = "google_drive_auth_token"
fun newInstance(preferences: SharedPreferences): GoogleDriveSyncProviderInfo? {
return GoogleDriveSyncProviderInfo()
val accessToken = preferences.getString(KEY_GOOGLE_DRIVE_AUTH_TOKEN, null) ?: return null
return GoogleDriveSyncProviderInfo(accessToken)
}
}
}

View File

@ -1,14 +1,11 @@
package org.mariotaku.twidere.util.sync.google
import android.content.Context
import com.google.android.gms.common.api.GoogleApiClient
import com.google.android.gms.drive.Drive
import com.google.android.gms.drive.DriveFile
import com.google.android.gms.drive.DriveId
import com.google.android.gms.drive.MetadataChangeSet
import com.google.api.client.util.DateTime
import com.google.api.services.drive.Drive
import com.google.api.services.drive.model.File
import org.mariotaku.twidere.extension.model.filename
import org.mariotaku.twidere.extension.model.readMimeMessageFrom
import org.mariotaku.twidere.extension.model.writeMimeMessageTo
import org.mariotaku.twidere.model.Draft
import org.mariotaku.twidere.util.sync.FileBasedDraftsSyncAction
import java.io.IOException
@ -16,18 +13,16 @@ import java.util.*
class GoogleDriveDraftsSyncAction(
context: Context,
val client: GoogleApiClient
val drive: Drive
) : FileBasedDraftsSyncAction<GoogleDriveDraftsSyncAction.DriveFileInfo>(context) {
@Throws(IOException::class)
override fun Draft.saveToRemote(): DriveFileInfo {
try {
val folder = Drive.DriveApi.getAppFolder(client)
val driveContents = Drive.DriveApi.newDriveContents(client).await().driveContents
this.writeMimeMessageTo(context, driveContents.outputStream)
val filename = "/Drafts/$filename"
val changeSet = MetadataChangeSet.Builder().setTitle(filename).build()
val driveFile = folder.createFile(client, changeSet, driveContents).await().driveFile
return DriveFileInfo(driveFile.driveId, filename, Date())
val modifiedTime = DateTime(timestamp)
val create = drive.files().create(File().setName(filename).setModifiedTime(modifiedTime))
val file = create.execute()
return DriveFileInfo(file.id, file.originalFilename, Date())
} catch (e: Exception) {
throw IOException(e)
}
@ -36,9 +31,8 @@ class GoogleDriveDraftsSyncAction(
@Throws(IOException::class)
override fun Draft.loadFromRemote(info: DriveFileInfo): Boolean {
try {
val file = info.driveId.asDriveFile()
val result = file.open(client, DriveFile.MODE_READ_ONLY, null).await()
result.driveContents.inputStream.use {
val get = drive.files().get(info.fileId)
get.executeAsInputStream().use {
val parsed = this.readMimeMessageFrom(context, it)
if (parsed) {
this.timestamp = info.draftTimestamp
@ -55,7 +49,7 @@ class GoogleDriveDraftsSyncAction(
override fun removeDrafts(list: List<DriveFileInfo>): Boolean {
try {
list.forEach { info ->
info.driveId.asDriveFile().delete(client).await()
drive.files().delete(info.fileId).execute()
}
return true
} catch (e: Exception) {
@ -66,7 +60,8 @@ class GoogleDriveDraftsSyncAction(
@Throws(IOException::class)
override fun removeDraft(info: DriveFileInfo): Boolean {
try {
return info.driveId.asDriveFile().delete(client).await().isSuccess
drive.files().delete(info.fileId).execute()
return true
} catch (e: Exception) {
throw IOException(e)
}
@ -78,12 +73,11 @@ class GoogleDriveDraftsSyncAction(
@Throws(IOException::class)
override fun listRemoteDrafts(): List<DriveFileInfo> {
val pendingResult = Drive.DriveApi.getAppFolder(client).listChildren(client)
val result = ArrayList<DriveFileInfo>()
try {
val requestResult = pendingResult.await()
requestResult.metadataBuffer.mapTo(result) { metadata ->
DriveFileInfo(metadata.driveId, metadata.originalFilename, metadata.modifiedDate)
val list = drive.files().list()
list.execute().files.mapTo(result) { file ->
DriveFileInfo(file.id, file.originalFilename, Date(file.modifiedTime.value))
}
} catch (e: Exception) {
throw IOException(e)
@ -91,6 +85,6 @@ class GoogleDriveDraftsSyncAction(
return result
}
data class DriveFileInfo(val driveId: DriveId, val name: String, val modifiedDate: Date)
data class DriveFileInfo(val fileId: String, val name: String, val modifiedDate: Date)
}

View File

@ -1,54 +1,37 @@
package org.mariotaku.twidere.util.sync.google
import android.content.ComponentCallbacks
import android.content.Context
import android.os.Bundle
import com.dropbox.core.DbxRequestConfig
import com.dropbox.core.v2.DbxClientV2
import com.google.android.gms.common.ConnectionResult
import com.google.android.gms.common.api.GoogleApiClient
import com.google.android.gms.drive.Drive
import com.google.api.client.googleapis.auth.oauth2.GoogleCredential
import com.google.api.client.http.javanet.NetHttpTransport
import com.google.api.client.json.jackson2.JacksonFactory
import com.google.api.services.drive.Drive
import nl.komponents.kovenant.task
import nl.komponents.kovenant.then
import nl.komponents.kovenant.ui.failUi
import nl.komponents.kovenant.ui.successUi
import org.mariotaku.twidere.BuildConfig
import org.mariotaku.twidere.util.TaskServiceRunner
import org.mariotaku.twidere.util.sync.ISyncAction
import org.mariotaku.twidere.util.sync.SyncTaskRunner
import org.mariotaku.twidere.util.sync.UserColorsSyncProcessor
import org.mariotaku.twidere.util.sync.UserNicknamesSyncProcessor
import org.mariotaku.twidere.util.sync.dropbox.DropboxDraftsSyncAction
import org.mariotaku.twidere.util.sync.dropbox.DropboxFiltersDataSyncAction
import org.mariotaku.twidere.util.sync.dropbox.DropboxPreferencesValuesSyncAction
import java.net.ConnectException
/**
* Created by mariotaku on 2017/1/6.
*/
class GoogleDriveSyncTaskRunner(context: Context) : SyncTaskRunner(context) {
class GoogleDriveSyncTaskRunner(context: Context, val accessToken: String) : SyncTaskRunner(context) {
override fun onRunningTask(action: String, callback: (Boolean) -> Unit): Boolean {
val client = GoogleApiClient.Builder(context)
.addApi(Drive.API)
.addScope(Drive.SCOPE_APPFOLDER)
.build()
val transport = NetHttpTransport.Builder().build()
val credential = GoogleCredential().setAccessToken(accessToken)
val drive = Drive.Builder(transport, JacksonFactory.getDefaultInstance(), credential).build()
val syncAction: ISyncAction = when (action) {
TaskServiceRunner.ACTION_SYNC_DRAFTS -> GoogleDriveDraftsSyncAction(context, client)
TaskServiceRunner.ACTION_SYNC_DRAFTS -> GoogleDriveDraftsSyncAction(context, drive)
else -> null
} ?: return false
task {
val connResult = client.blockingConnect()
if (!connResult.isSuccess) {
throw ConnectException()
}
syncAction.execute()
}.successUi {
callback(true)
}.failUi {
callback(false)
}.always {
client.disconnect()
}
return true
}