Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

F-droid fixes #2981

Merged
merged 4 commits into from
Nov 2, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 19 additions & 10 deletions app/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -301,6 +301,14 @@ kotlin {
jvmToolchain(jvmToolChainVersion)
}

if(gradle.startParameter.taskNames.any { it.contains("Fdroid") }) {
println("Fdroid build: excluding Google Drive stuff")
tasks.withType<org.jetbrains.kotlin.gradle.tasks.KotlinCompile> {
println("Excluding ${name}")
exclude("**/googledrive/*")
}
}

androidComponents {
val discreteSelector = selector().withFlavor(dimAppearanceName to discreteFlavorName )
// Set the applicationId to a more discrete alternative.
Expand Down Expand Up @@ -351,16 +359,17 @@ dependencies {
implementation("net.objecthunter:exp4j:0.4.8")
implementation("com.github.requery:sqlite-android:$sqliteAndroidVersion")


// Google Drive API
implementation("com.google.android.gms:play-services-auth:20.7.0")
implementation ("com.google.apis:google-api-services-drive:v3-rev20230212-2.0.0") {
exclude("org.apache.httpcomponents")
exclude("com.google.guava.guava")
}
implementation("com.google.guava:guava:32.0.1-android")
implementation("com.google.api-client:google-api-client-android:2.2.0") {
exclude("org.apache.httpcomponents")
//// Google Drive API
for(variantImplementation in listOf("googleplay", "github", "amazon", "samsung", "huawei").map { "${it}Implementation" }) {
variantImplementation("com.google.android.gms:play-services-auth:20.7.0")
variantImplementation("com.google.apis:google-api-services-drive:v3-rev20230212-2.0.0") {
exclude("org.apache.httpcomponents")
exclude("com.google.guava.guava")
}
variantImplementation("com.google.guava:guava:32.0.1-android")
variantImplementation("com.google.api-client:google-api-client-android:2.2.0") {
exclude("org.apache.httpcomponents")
}
}

//implementation("androidx.recyclerview:recyclerview-selection:1.0.0")
Expand Down
5 changes: 2 additions & 3 deletions app/src/main/java/net/bible/service/cloudsync/CloudAdapter.kt
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@

package net.bible.service.cloudsync

import com.google.api.client.util.DateTime
import net.bible.android.view.activity.base.ActivityBase
import java.io.File
import java.io.OutputStream
Expand All @@ -26,7 +25,7 @@ data class CloudFile(
val id: String,
val name: String,
val size: Long,
val createdTime: DateTime,
val createdTime: Long,
val parentId: String
)

Expand All @@ -39,7 +38,7 @@ interface CloudAdapter {
parentsIds: List<String>? = null,
name: String? = null,
mimeType: String? = null,
createdTimeAtLeast: DateTime? = null
createdTimeAtLeast: Long? = null
): List<CloudFile>
fun getFolders(parentId: String): List<CloudFile>
fun download(id: String, outputStream: OutputStream)
Expand Down
45 changes: 14 additions & 31 deletions app/src/main/java/net/bible/service/cloudsync/CloudSync.kt
Original file line number Diff line number Diff line change
Expand Up @@ -21,12 +21,9 @@ import android.app.AlertDialog
import android.content.Intent
import android.os.Build
import android.util.Log
import com.google.android.gms.tasks.Task
import com.google.api.client.util.DateTime
import io.requery.android.database.sqlite.SQLiteDatabase
import kotlinx.coroutines.CompletableDeferred
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.suspendCancellableCoroutine
import kotlinx.coroutines.sync.Mutex
import kotlinx.coroutines.sync.withLock
import kotlinx.coroutines.withContext
Expand All @@ -37,34 +34,17 @@ import net.bible.android.database.SyncStatus
import net.bible.android.view.activity.base.ActivityBase
import net.bible.android.view.activity.base.CurrentActivityHolder
import net.bible.android.view.activity.base.Dialogs
import net.bible.android.view.activity.page.MainBibleActivity
import net.bible.android.view.activity.page.application
import net.bible.service.common.CommonUtils
import net.bible.service.common.asyncMap
import net.bible.service.db.DatabaseContainer
import java.io.FileNotFoundException
import java.io.IOException
import java.net.SocketTimeoutException
import kotlin.coroutines.resume
import kotlin.coroutines.resumeWithException
import kotlin.coroutines.suspendCoroutine

const val webClientId = "533479479097-kk5bfksbgtfuq3gfkkrt2eb51ltgkvmn.apps.googleusercontent.com"
const val FOLDER_MIMETYPE = "application/vnd.google-apps.folder"
const val GZIP_MIMETYPE = "application/gzip"

suspend fun <T> Task<T>.await(): T = suspendCancellableCoroutine { continuation ->
addOnSuccessListener { result ->
continuation.resume(result, null)
}
addOnFailureListener { exception ->
continuation.resumeWithException(exception)
}
addOnCanceledListener {
continuation.cancel()
}
}

const val SYNC_FOLDER_FILE_ID_KEY = "syncId"
const val SYNC_DEVICE_FOLDER_FILE_ID_KEY = "deviceFolderId"
const val LAST_PATCH_WRITTEN_KEY = "lastPatchWritten"
Expand All @@ -82,7 +62,11 @@ enum class CloudAdapters {
GOOGLE_DRIVE -> R.string.adapters_google_drive
}
val newAdapter: CloudAdapter get() = when(this) {
GOOGLE_DRIVE -> GoogleDriveCloudAdapter()
GOOGLE_DRIVE -> {
val adapter = Class.forName("net.bible.service.cloudsync.googledrive.GoogleDriveCloudAdapter")
val constructor = adapter.getDeclaredConstructor()
constructor.newInstance() as CloudAdapter
}
}

companion object {
Expand Down Expand Up @@ -271,7 +255,7 @@ object CloudSync {
file = gzippedTmpFile,
parentId = dbDef.dao.getString(SYNC_FOLDER_FILE_ID_KEY)!!
)
dbDef.dao.addStatus(SyncStatus(CommonUtils.deviceIdentifier, 0, result.size, result.createdTime.value))
dbDef.dao.addStatus(SyncStatus(CommonUtils.deviceIdentifier, 0, result.size, result.createdTime))
gzippedTmpFile.delete()
}

Expand Down Expand Up @@ -311,7 +295,7 @@ object CloudSync {
CommonUtils.deviceIdentifier,
0,
initialFile.size,
initialFile.createdTime.value
initialFile.createdTime
)
)
ABEventBus.post(WorkspaceRefreshRequired())
Expand Down Expand Up @@ -428,11 +412,10 @@ object CloudSync {
class IncompatiblePatchVersion: Exception()
private suspend fun downloadAndApplyNewPatches(dbDef: SyncableDatabaseAccessor<*>) = withContext(Dispatchers.IO) {
val lastSynchronized = dbDef.dao.getLong(LAST_SYNCHRONIZED_KEY)?: 0
val lastSynchronizedDateTime = DateTime(lastSynchronized)
val syncFolder = dbDef.dao.getString(SYNC_FOLDER_FILE_ID_KEY)!!
val deviceSyncFolder = dbDef.dao.getString(SYNC_DEVICE_FOLDER_FILE_ID_KEY)!!

Log.i(TAG, "Downloading new patches ${dbDef.categoryName}, last Synced: $lastSynchronizedDateTime. ")
Log.i(TAG, "Downloading new patches ${dbDef.categoryName}, last Synced: $lastSynchronized. ")
Log.i(TAG, "This device ${CommonUtils.deviceIdentifier} (id: ${deviceSyncFolder})")

dbDef.dao.setConfig(LAST_SYNCHRONIZED_KEY, System.currentTimeMillis())
Expand All @@ -447,8 +430,8 @@ object CloudSync {

val patchResults = adapter.listFiles(
parentsIds = folderResult.map { it.id },
createdTimeAtLeast = lastSynchronizedDateTime
).sortedBy { it.createdTime.value }
createdTimeAtLeast = lastSynchronized
).sortedBy { it.createdTime }

Log.i(TAG, "Number of patch files in result set: ${patchResults.size}")

Expand All @@ -472,7 +455,7 @@ object CloudSync {
if (existing == null && num > folderWithMeta.loadedCount) {
DriveFileWithMeta(it, folderWithMeta.folder.name)
} else null
}.sortedBy { it.file.createdTime.value }
}.sortedBy { it.file.createdTime }

if(patches.isEmpty()) {
Log.i(TAG, "No patches, returning")
Expand Down Expand Up @@ -500,7 +483,7 @@ object CloudSync {
}

val syncStatuses = patches.map {
SyncStatus(it.parentFolderName, patchNumber(it.file.name), it.file.size, it.file.createdTime.value)
SyncStatus(it.parentFolderName, patchNumber(it.file.name), it.file.size, it.file.createdTime)
}

applyPatchesForDatabase(dbDef, *downloadedFiles.toTypedArray())
Expand All @@ -523,9 +506,9 @@ object CloudSync {
file.delete()
throw e
}
Log.i(TAG, "Uploaded ${dbDef.categoryName} $fileName, ${file.length()} bytes, ${result.createdTime.toStringRfc3339()}")
Log.i(TAG, "Uploaded ${dbDef.categoryName} $fileName, ${file.length()} bytes, ${result.createdTime}")
dbDef.dao.setConfig(LAST_PATCH_WRITTEN_KEY, lastWritten)
dbDef.dao.addStatus(SyncStatus(CommonUtils.deviceIdentifier, count, file.length(), result.createdTime.value))
dbDef.dao.addStatus(SyncStatus(CommonUtils.deviceIdentifier, count, file.length(), result.createdTime))
file.delete()
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
* If not, see http://www.gnu.org/licenses/.
*/

package net.bible.service.cloudsync
package net.bible.service.cloudsync.googledrive

import android.accounts.Account
import android.app.Activity
Expand All @@ -26,6 +26,7 @@ import com.google.android.gms.auth.api.identity.BeginSignInRequest
import com.google.android.gms.auth.api.identity.Identity
import com.google.android.gms.auth.api.identity.SignInClient
import com.google.android.gms.auth.api.identity.SignInCredential
import com.google.android.gms.tasks.Task
import com.google.api.client.googleapis.extensions.android.gms.auth.GoogleAccountCredential
import com.google.api.client.googleapis.extensions.android.gms.auth.UserRecoverableAuthIOException
import com.google.api.client.googleapis.json.GoogleJsonResponseException
Expand All @@ -37,21 +38,30 @@ import com.google.api.services.drive.model.File as DriveFile
import com.google.api.services.drive.Drive
import com.google.api.services.drive.DriveScopes
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.suspendCancellableCoroutine
import kotlinx.coroutines.withContext
import net.bible.android.BibleApplication
import net.bible.android.view.activity.base.ActivityBase
import net.bible.service.cloudsync.CloudAdapter
import net.bible.service.cloudsync.CloudFile
import net.bible.service.cloudsync.GZIP_MIMETYPE
import net.bible.service.cloudsync.TAG
import net.bible.service.common.CommonUtils
import java.io.File
import java.io.FileNotFoundException
import java.io.IOException
import java.io.OutputStream
import java.util.Collections
import kotlin.coroutines.resumeWithException

const val webClientId = "533479479097-kk5bfksbgtfuq3gfkkrt2eb51ltgkvmn.apps.googleusercontent.com"
const val FOLDER_MIMETYPE = "application/vnd.google-apps.folder"

fun DriveFile.toSyncFile() = CloudFile(
id = id,
name = name,
size = getSize()?: 0,
createdTime = createdTime,
createdTime = createdTime.value,
parentId = parents.first()
)

Expand All @@ -66,6 +76,18 @@ fun Drive.Files.List.collectAll(): List<DriveFile> {
return result
}

suspend fun <T> Task<T>.await(): T = suspendCancellableCoroutine { continuation ->
addOnSuccessListener { result ->
continuation.resume(result, null)
}
addOnFailureListener { exception ->
continuation.resumeWithException(exception)
}
addOnCanceledListener {
continuation.cancel()
}
}

private const val FIELDS = "id, name, size, createdTime, parents"


Expand Down Expand Up @@ -189,8 +211,9 @@ class GoogleDriveCloudAdapter: CloudAdapter {
parentsIds: List<String>?,
name: String?,
mimeType: String?,
createdTimeAtLeast: DateTime?
createdTimeAtLeast: Long?
): List<CloudFile> {
val createdTimeAtLeastDateTime = createdTimeAtLeast?.let { DateTime(it) }
val q = mutableListOf<String>()
if (parentsIds != null) {
q.add(
Expand All @@ -201,9 +224,9 @@ class GoogleDriveCloudAdapter: CloudAdapter {
) { "'$it' in parents" }
)
}
if(createdTimeAtLeast != null) {
if(createdTimeAtLeastDateTime != null) {
q.add(
"createdTime > '${createdTimeAtLeast.toStringRfc3339()}'"
"createdTime > '${createdTimeAtLeastDateTime.toStringRfc3339()}'"
)
}
if(name != null) {
Expand Down
6 changes: 5 additions & 1 deletion app/src/main/java/net/bible/service/common/CommonUtils.kt
Original file line number Diff line number Diff line change
Expand Up @@ -1495,7 +1495,11 @@ object CommonUtils : CommonUtilsBase() {
}
}

val isCloudSyncAvailable get() = !(BuildVariant.Appearance.isDiscrete || Build.VERSION.SDK_INT <= Build.VERSION_CODES.LOLLIPOP_MR1)
val isCloudSyncAvailable get() = !(
BuildVariant.Appearance.isDiscrete
|| BuildVariant.DistributionChannel.isFdroid
|| Build.VERSION.SDK_INT <= Build.VERSION_CODES.LOLLIPOP_MR1
)

val isCloudSyncEnabled: Boolean get () =
if(!isCloudSyncAvailable) false
Expand Down