using drive web api
This commit is contained in:
parent
f8c65e0269
commit
fe72d897be
|
@ -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'
|
||||
|
|
|
@ -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
|
||||
}
|
||||
}
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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)
|
||||
|
||||
}
|
|
@ -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
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue