Repo Created
This commit is contained in:
parent
eb305e2886
commit
a8c22c65db
4784 changed files with 329907 additions and 2 deletions
45
play-services-auth-blockstore/build.gradle
Normal file
45
play-services-auth-blockstore/build.gradle
Normal file
|
|
@ -0,0 +1,45 @@
|
|||
/*
|
||||
* SPDX-FileCopyrightText: 2025 microG Project Team
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
// Metadata derived from play-services-auth-blockstore:16.4.0
|
||||
|
||||
apply plugin: 'com.android.library'
|
||||
apply plugin: 'maven-publish'
|
||||
apply plugin: 'signing'
|
||||
|
||||
android {
|
||||
namespace "com.google.android.gms.auth.blockstore"
|
||||
|
||||
compileSdkVersion androidCompileSdk
|
||||
buildToolsVersion "$androidBuildVersionTools"
|
||||
|
||||
buildFeatures {
|
||||
aidl = true
|
||||
}
|
||||
|
||||
defaultConfig {
|
||||
versionName version
|
||||
minSdkVersion androidMinSdk
|
||||
targetSdkVersion androidTargetSdk
|
||||
}
|
||||
|
||||
compileOptions {
|
||||
sourceCompatibility = 1.8
|
||||
targetCompatibility = 1.8
|
||||
}
|
||||
}
|
||||
|
||||
apply from: '../gradle/publish-android.gradle'
|
||||
|
||||
description = 'microG implementation of play-services-auth-blockstore'
|
||||
|
||||
dependencies {
|
||||
api project(':play-services-base')
|
||||
api project(':play-services-basement')
|
||||
api project(':play-services-tasks')
|
||||
api 'org.jetbrains.kotlin:kotlin-stdlib:1.9.0'
|
||||
|
||||
annotationProcessor project(':safe-parcel-processor')
|
||||
}
|
||||
42
play-services-auth-blockstore/core/build.gradle
Normal file
42
play-services-auth-blockstore/core/build.gradle
Normal file
|
|
@ -0,0 +1,42 @@
|
|||
/*
|
||||
* SPDX-FileCopyrightText: 2025 microG Project Team
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
apply plugin: 'com.android.library'
|
||||
apply plugin: 'kotlin-android'
|
||||
|
||||
dependencies {
|
||||
api project(':play-services-auth-blockstore')
|
||||
implementation project(':play-services-base-core')
|
||||
}
|
||||
|
||||
android {
|
||||
namespace "org.microg.gms.auth.blockstore"
|
||||
|
||||
compileSdkVersion androidCompileSdk
|
||||
buildToolsVersion "$androidBuildVersionTools"
|
||||
|
||||
defaultConfig {
|
||||
versionName version
|
||||
minSdkVersion androidMinSdk
|
||||
targetSdkVersion androidTargetSdk
|
||||
}
|
||||
|
||||
sourceSets {
|
||||
main.java.srcDirs += 'src/main/kotlin'
|
||||
}
|
||||
|
||||
compileOptions {
|
||||
sourceCompatibility = 1.8
|
||||
targetCompatibility = 1.8
|
||||
}
|
||||
|
||||
kotlinOptions {
|
||||
jvmTarget = 1.8
|
||||
}
|
||||
|
||||
lintOptions {
|
||||
disable 'MissingTranslation', 'GetLocales'
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,18 @@
|
|||
<?xml version="1.0" encoding="utf-8"?><!--
|
||||
~ SPDX-FileCopyrightText: 2025 microG Project Team
|
||||
~ SPDX-License-Identifier: Apache-2.0
|
||||
-->
|
||||
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools">
|
||||
|
||||
<application>
|
||||
|
||||
<service android:name="org.microg.gms.auth.blockstore.BlockstoreApiService">
|
||||
<intent-filter>
|
||||
<action android:name="com.google.android.gms.auth.blockstore.service.START" />
|
||||
</intent-filter>
|
||||
</service>
|
||||
|
||||
</application>
|
||||
</manifest>
|
||||
|
|
@ -0,0 +1,89 @@
|
|||
/*
|
||||
* SPDX-FileCopyrightText: 2025 microG Project Team
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
package org.microg.gms.auth.blockstore
|
||||
|
||||
import android.content.Context
|
||||
import android.content.SharedPreferences
|
||||
import android.os.Bundle
|
||||
import android.util.Base64
|
||||
import android.util.Log
|
||||
import com.google.android.gms.auth.blockstore.BlockstoreClient
|
||||
import com.google.android.gms.auth.blockstore.BlockstoreStatusCodes
|
||||
import com.google.android.gms.auth.blockstore.DeleteBytesRequest
|
||||
import com.google.android.gms.auth.blockstore.RetrieveBytesRequest
|
||||
import com.google.android.gms.auth.blockstore.RetrieveBytesResponse
|
||||
import com.google.android.gms.auth.blockstore.StoreBytesData
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.withContext
|
||||
import org.microg.gms.utils.toBase64
|
||||
|
||||
private const val SHARED_PREFS_NAME = "com.google.android.gms.blockstore"
|
||||
|
||||
private const val TAG = "BlockStoreImpl"
|
||||
|
||||
class BlockStoreImpl(context: Context, val callerPackage: String) {
|
||||
|
||||
private val blockStoreSp: SharedPreferences by lazy {
|
||||
context.getSharedPreferences(SHARED_PREFS_NAME, Context.MODE_PRIVATE)
|
||||
}
|
||||
|
||||
private fun initSpByPackage(): Map<String, *>? {
|
||||
val map = blockStoreSp.all
|
||||
if (map.isNullOrEmpty() || map.all { !it.key.startsWith(callerPackage) }) return null
|
||||
return map.filter { it.key.startsWith(callerPackage) }
|
||||
}
|
||||
|
||||
suspend fun deleteBytesWithRequest(request: DeleteBytesRequest?): Boolean = withContext(Dispatchers.IO) {
|
||||
Log.d(TAG, "deleteBytesWithRequest: callerPackage: $callerPackage")
|
||||
val localData = initSpByPackage()
|
||||
if (request == null || localData.isNullOrEmpty()) return@withContext false
|
||||
if (request.deleteAll) {
|
||||
localData.keys.forEach { blockStoreSp.edit()?.remove(it)?.commit() }
|
||||
} else {
|
||||
request.keys.forEach { blockStoreSp.edit()?.remove("$callerPackage:$it")?.commit() }
|
||||
}
|
||||
true
|
||||
}
|
||||
|
||||
suspend fun retrieveBytesWithRequest(request: RetrieveBytesRequest?): RetrieveBytesResponse? = withContext(Dispatchers.IO) {
|
||||
Log.d(TAG, "retrieveBytesWithRequest: callerPackage: $callerPackage")
|
||||
val localData = initSpByPackage()
|
||||
if (request == null || localData.isNullOrEmpty()) return@withContext null
|
||||
val data = mutableListOf<RetrieveBytesResponse.BlockstoreData>()
|
||||
val filterKeys = if (request.keys.isNullOrEmpty()) emptyList<String>() else request.keys
|
||||
for (key in localData.keys) {
|
||||
val bytesKey = key.substring(callerPackage.length + 1)
|
||||
if (filterKeys.isNotEmpty() && !filterKeys.contains(bytesKey)) continue
|
||||
val bytes = blockStoreSp.getString(key, null)?.let { Base64.decode(it, Base64.URL_SAFE) } ?: continue
|
||||
data.add(RetrieveBytesResponse.BlockstoreData(bytes, bytesKey))
|
||||
}
|
||||
RetrieveBytesResponse(Bundle.EMPTY, data)
|
||||
}
|
||||
|
||||
suspend fun retrieveBytes(): ByteArray? = withContext(Dispatchers.IO) {
|
||||
Log.d(TAG, "retrieveBytes: callerPackage: $callerPackage")
|
||||
val localData = initSpByPackage()
|
||||
if (localData.isNullOrEmpty()) return@withContext null
|
||||
val savedKey = localData.keys.firstOrNull { it == "$callerPackage:${BlockstoreClient.DEFAULT_BYTES_DATA_KEY}" } ?: return@withContext null
|
||||
blockStoreSp.getString(savedKey, null)?.let { Base64.decode(it, Base64.URL_SAFE) }
|
||||
}
|
||||
|
||||
suspend fun storeBytes(data: StoreBytesData?): Int = withContext(Dispatchers.IO) {
|
||||
if (data == null || data.bytes == null) return@withContext 0
|
||||
val localData = initSpByPackage()
|
||||
if ((localData?.size ?: 0) >= BlockstoreClient.MAX_ENTRY_COUNT) {
|
||||
return@withContext BlockstoreStatusCodes.TOO_MANY_ENTRIES
|
||||
}
|
||||
val bytes = data.bytes
|
||||
if (bytes.size > BlockstoreClient.MAX_SIZE) {
|
||||
return@withContext BlockstoreStatusCodes.MAX_SIZE_EXCEEDED
|
||||
}
|
||||
val savedKey = "$callerPackage:${data.key ?: BlockstoreClient.DEFAULT_BYTES_DATA_KEY}"
|
||||
val base64 = bytes.toBase64(Base64.URL_SAFE)
|
||||
val bool = blockStoreSp.edit()?.putString(savedKey, base64)?.commit()
|
||||
if (bool == true) bytes.size else 0
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,163 @@
|
|||
/*
|
||||
* SPDX-FileCopyrightText: 2025 microG Project Team
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
package org.microg.gms.auth.blockstore
|
||||
|
||||
import android.os.Bundle
|
||||
import android.util.Log
|
||||
import androidx.lifecycle.Lifecycle
|
||||
import androidx.lifecycle.LifecycleOwner
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import com.google.android.gms.auth.blockstore.AppRestoreInfo
|
||||
import com.google.android.gms.auth.blockstore.BlockstoreStatusCodes
|
||||
import com.google.android.gms.auth.blockstore.DeleteBytesRequest
|
||||
import com.google.android.gms.auth.blockstore.RetrieveBytesRequest
|
||||
import com.google.android.gms.auth.blockstore.RetrieveBytesResponse
|
||||
import com.google.android.gms.auth.blockstore.StoreBytesData
|
||||
import com.google.android.gms.auth.blockstore.internal.IBlockstoreService
|
||||
import com.google.android.gms.auth.blockstore.internal.IDeleteBytesCallback
|
||||
import com.google.android.gms.auth.blockstore.internal.IGetAccessForPackageCallback
|
||||
import com.google.android.gms.auth.blockstore.internal.IGetBlockstoreDataCallback
|
||||
import com.google.android.gms.auth.blockstore.internal.IIsEndToEndEncryptionAvailableCallback
|
||||
import com.google.android.gms.auth.blockstore.internal.IRetrieveBytesCallback
|
||||
import com.google.android.gms.auth.blockstore.internal.ISetBlockstoreDataCallback
|
||||
import com.google.android.gms.auth.blockstore.internal.IStoreBytesCallback
|
||||
import com.google.android.gms.common.Feature
|
||||
import com.google.android.gms.common.api.CommonStatusCodes
|
||||
import com.google.android.gms.common.api.Status
|
||||
import com.google.android.gms.common.api.internal.IStatusCallback
|
||||
import com.google.android.gms.common.internal.ConnectionInfo
|
||||
import com.google.android.gms.common.internal.GetServiceRequest
|
||||
import com.google.android.gms.common.internal.IGmsCallbacks
|
||||
import kotlinx.coroutines.launch
|
||||
import org.microg.gms.BaseService
|
||||
import org.microg.gms.common.GmsService
|
||||
import org.microg.gms.common.GmsService.BLOCK_STORE
|
||||
import org.microg.gms.common.PackageUtils
|
||||
|
||||
private const val TAG = "BlockstoreApiService"
|
||||
|
||||
private val FEATURES = arrayOf(
|
||||
Feature("auth_blockstore", 3),
|
||||
Feature("blockstore_data_transfer", 1),
|
||||
Feature("blockstore_notify_app_restore", 1),
|
||||
Feature("blockstore_store_bytes_with_options", 2),
|
||||
Feature("blockstore_is_end_to_end_encryption_available", 1),
|
||||
Feature("blockstore_enable_cloud_backup", 1),
|
||||
Feature("blockstore_delete_bytes", 2),
|
||||
Feature("blockstore_retrieve_bytes_with_options", 3),
|
||||
Feature("auth_clear_restore_credential", 2),
|
||||
Feature("auth_create_restore_credential", 1),
|
||||
Feature("auth_get_restore_credential", 1),
|
||||
Feature("auth_get_private_restore_credential_key", 1),
|
||||
Feature("auth_set_private_restore_credential_key", 1),
|
||||
)
|
||||
|
||||
class BlockstoreApiService : BaseService(TAG, BLOCK_STORE) {
|
||||
|
||||
override fun handleServiceRequest(callback: IGmsCallbacks, request: GetServiceRequest, service: GmsService) {
|
||||
try {
|
||||
val packageName = PackageUtils.getAndCheckCallingPackage(this, request.packageName) ?: throw IllegalArgumentException("Missing package name")
|
||||
|
||||
val blockStoreImpl = BlockStoreImpl(this, packageName)
|
||||
callback.onPostInitCompleteWithConnectionInfo(
|
||||
CommonStatusCodes.SUCCESS, BlobstoreServiceImpl(blockStoreImpl, lifecycle).asBinder(), ConnectionInfo().apply { features = FEATURES })
|
||||
} catch (e: Exception) {
|
||||
Log.w(TAG, "handleServiceRequest", e)
|
||||
callback.onPostInitComplete(CommonStatusCodes.INTERNAL_ERROR, null, null)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class BlobstoreServiceImpl(val blockStore: BlockStoreImpl, override val lifecycle: Lifecycle) : IBlockstoreService.Stub(), LifecycleOwner {
|
||||
|
||||
override fun retrieveBytes(callback: IRetrieveBytesCallback?) {
|
||||
Log.d(TAG, "Method (retrieveBytes) called")
|
||||
lifecycleScope.launch {
|
||||
runCatching {
|
||||
val retrieveBytes = blockStore.retrieveBytes()
|
||||
if (retrieveBytes != null) {
|
||||
callback?.onBytesResult(Status.SUCCESS, retrieveBytes)
|
||||
} else {
|
||||
callback?.onBytesResult(Status.INTERNAL_ERROR, null)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun setBlockstoreData(callback: ISetBlockstoreDataCallback?, data: ByteArray?) {
|
||||
Log.d(TAG, "Method (setBlockstoreData: ${data?.size}) called but not implemented")
|
||||
}
|
||||
|
||||
override fun getBlockstoreData(callback: IGetBlockstoreDataCallback?) {
|
||||
Log.d(TAG, "Method (getBlockstoreData) called but not implemented")
|
||||
}
|
||||
|
||||
override fun getAccessForPackage(callback: IGetAccessForPackageCallback?, packageName: String?) {
|
||||
Log.d(TAG, "Method (getAccessForPackage: $packageName) called but not implemented")
|
||||
}
|
||||
|
||||
override fun setFlagWithPackage(callback: IStatusCallback?, packageName: String?, flag: Int) {
|
||||
Log.d(TAG, "Method (setFlagWithPackage: $packageName, $flag) called but not implemented")
|
||||
}
|
||||
|
||||
override fun clearFlagForPackage(callback: IStatusCallback?, packageName: String?) {
|
||||
Log.d(TAG, "Method (clearFlagForPackage: $packageName) called but not implemented")
|
||||
}
|
||||
|
||||
override fun updateFlagForPackage(callback: IStatusCallback?, packageName: String?, value: Int) {
|
||||
Log.d(TAG, "Method (updateFlagForPackage: $packageName, $value) called but not implemented")
|
||||
}
|
||||
|
||||
override fun reportAppRestore(callback: IStatusCallback?, packages: List<String?>?, code: Int, info: AppRestoreInfo?) {
|
||||
Log.d(TAG, "Method (reportAppRestore: $packages, $code, $info) called but not implemented")
|
||||
}
|
||||
|
||||
override fun storeBytes(callback: IStoreBytesCallback?, data: StoreBytesData?) {
|
||||
Log.d(TAG, "Method (storeBytes: $data) called")
|
||||
lifecycleScope.launch {
|
||||
runCatching {
|
||||
val storeBytes = blockStore.storeBytes(data)
|
||||
Log.d(TAG, "storeBytes: size: $storeBytes")
|
||||
when (storeBytes) {
|
||||
0 -> callback?.onStoreBytesResult(Status.INTERNAL_ERROR, BlockstoreStatusCodes.FEATURE_NOT_SUPPORTED)
|
||||
BlockstoreStatusCodes.MAX_SIZE_EXCEEDED -> callback?.onStoreBytesResult(Status.INTERNAL_ERROR, BlockstoreStatusCodes.MAX_SIZE_EXCEEDED)
|
||||
BlockstoreStatusCodes.TOO_MANY_ENTRIES -> callback?.onStoreBytesResult(Status.INTERNAL_ERROR, BlockstoreStatusCodes.TOO_MANY_ENTRIES)
|
||||
else -> callback?.onStoreBytesResult(Status.SUCCESS, storeBytes)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun isEndToEndEncryptionAvailable(callback: IIsEndToEndEncryptionAvailableCallback?) {
|
||||
Log.d(TAG, "Method (isEndToEndEncryptionAvailable) called")
|
||||
runCatching { callback?.onCheckEndToEndEncryptionResult(Status.SUCCESS, false) }
|
||||
}
|
||||
|
||||
override fun retrieveBytesWithRequest(callback: IRetrieveBytesCallback?, request: RetrieveBytesRequest?) {
|
||||
Log.d(TAG, "Method (retrieveBytesWithRequest: $request) called")
|
||||
lifecycleScope.launch {
|
||||
runCatching {
|
||||
val retrieveBytesResponse = blockStore.retrieveBytesWithRequest(request)
|
||||
Log.d(TAG, "retrieveBytesWithRequest: retrieveBytesResponse: $retrieveBytesResponse")
|
||||
if (retrieveBytesResponse != null) {
|
||||
callback?.onResponseResult(Status.SUCCESS, retrieveBytesResponse)
|
||||
} else {
|
||||
callback?.onResponseResult(Status.INTERNAL_ERROR, RetrieveBytesResponse(Bundle.EMPTY, emptyList()))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun deleteBytes(callback: IDeleteBytesCallback?, request: DeleteBytesRequest?) {
|
||||
Log.d(TAG, "Method (deleteBytes: $request) called")
|
||||
lifecycleScope.launch {
|
||||
runCatching {
|
||||
val deleted = blockStore.deleteBytesWithRequest(request)
|
||||
callback?.onDeleteBytesResult(Status.SUCCESS, deleted)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,6 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
~ SPDX-FileCopyrightText: 2025 microG Project Team
|
||||
~ SPDX-License-Identifier: Apache-2.0
|
||||
-->
|
||||
<manifest />
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
/*
|
||||
* SPDX-FileCopyrightText: 2025 microG Project Team
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
package com.google.android.gms.auth.blockstore;
|
||||
|
||||
parcelable AppRestoreInfo;
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
/*
|
||||
* SPDX-FileCopyrightText: 2025 microG Project Team
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
package com.google.android.gms.auth.blockstore;
|
||||
|
||||
parcelable DeleteBytesRequest;
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
/*
|
||||
* SPDX-FileCopyrightText: 2025 microG Project Team
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
package com.google.android.gms.auth.blockstore;
|
||||
|
||||
parcelable RetrieveBytesRequest;
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
/*
|
||||
* SPDX-FileCopyrightText: 2025 microG Project Team
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
package com.google.android.gms.auth.blockstore;
|
||||
|
||||
parcelable RetrieveBytesResponse;
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
/*
|
||||
* SPDX-FileCopyrightText: 2025 microG Project Team
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
package com.google.android.gms.auth.blockstore;
|
||||
|
||||
parcelable StoreBytesData;
|
||||
|
|
@ -0,0 +1,36 @@
|
|||
/*
|
||||
* SPDX-FileCopyrightText: 2025 microG Project Team
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
package com.google.android.gms.auth.blockstore.internal;
|
||||
|
||||
import com.google.android.gms.common.api.Status;
|
||||
import android.os.Bundle;
|
||||
import com.google.android.gms.auth.blockstore.AppRestoreInfo;
|
||||
import com.google.android.gms.auth.blockstore.DeleteBytesRequest;
|
||||
import com.google.android.gms.auth.blockstore.RetrieveBytesRequest;
|
||||
import com.google.android.gms.auth.blockstore.StoreBytesData;
|
||||
import com.google.android.gms.common.api.internal.IStatusCallback;
|
||||
import com.google.android.gms.auth.blockstore.internal.IRetrieveBytesCallback;
|
||||
import com.google.android.gms.auth.blockstore.internal.ISetBlockstoreDataCallback;
|
||||
import com.google.android.gms.auth.blockstore.internal.IGetBlockstoreDataCallback;
|
||||
import com.google.android.gms.auth.blockstore.internal.IGetAccessForPackageCallback;
|
||||
import com.google.android.gms.auth.blockstore.internal.IStoreBytesCallback;
|
||||
import com.google.android.gms.auth.blockstore.internal.IIsEndToEndEncryptionAvailableCallback;
|
||||
import com.google.android.gms.auth.blockstore.internal.IDeleteBytesCallback;
|
||||
|
||||
interface IBlockstoreService {
|
||||
void retrieveBytes(IRetrieveBytesCallback callback) = 1;
|
||||
void setBlockstoreData(ISetBlockstoreDataCallback callback, in byte[] data) = 2;
|
||||
void getBlockstoreData(IGetBlockstoreDataCallback callback) = 3;
|
||||
void getAccessForPackage(IGetAccessForPackageCallback callback, String packageName) = 4;
|
||||
void setFlagWithPackage(IStatusCallback callback, String packageName, int flag) = 5;
|
||||
void clearFlagForPackage(IStatusCallback callback, String packageName) = 6;
|
||||
void updateFlagForPackage(IStatusCallback callback, String packageName, int value) = 7;
|
||||
void reportAppRestore(IStatusCallback callback, in List<String> packages, int code, in AppRestoreInfo info) = 8;
|
||||
void storeBytes(IStoreBytesCallback callback, in StoreBytesData data) = 9;
|
||||
void isEndToEndEncryptionAvailable(IIsEndToEndEncryptionAvailableCallback callback) = 10;
|
||||
void retrieveBytesWithRequest(IRetrieveBytesCallback callback, in RetrieveBytesRequest request) = 11;
|
||||
void deleteBytes(IDeleteBytesCallback callback, in DeleteBytesRequest request) = 12;
|
||||
}
|
||||
|
|
@ -0,0 +1,12 @@
|
|||
/*
|
||||
* SPDX-FileCopyrightText: 2025 microG Project Team
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
package com.google.android.gms.auth.blockstore.internal;
|
||||
|
||||
import com.google.android.gms.common.api.Status;
|
||||
|
||||
interface IDeleteBytesCallback {
|
||||
void onDeleteBytesResult(in Status status, boolean deleted);
|
||||
}
|
||||
|
|
@ -0,0 +1,12 @@
|
|||
/*
|
||||
* SPDX-FileCopyrightText: 2025 microG Project Team
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
package com.google.android.gms.auth.blockstore.internal;
|
||||
|
||||
import com.google.android.gms.common.api.Status;
|
||||
|
||||
interface IGetAccessForPackageCallback {
|
||||
void onGetAccessResult(in Status status, int accessResult);
|
||||
}
|
||||
|
|
@ -0,0 +1,12 @@
|
|||
/*
|
||||
* SPDX-FileCopyrightText: 2025 microG Project Team
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
package com.google.android.gms.auth.blockstore.internal;
|
||||
|
||||
import com.google.android.gms.common.api.Status;
|
||||
|
||||
interface IGetBlockstoreDataCallback {
|
||||
void onGetBlockstoreData(in Status status, in byte[] dataBytes);
|
||||
}
|
||||
|
|
@ -0,0 +1,12 @@
|
|||
/*
|
||||
* SPDX-FileCopyrightText: 2025 microG Project Team
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
package com.google.android.gms.auth.blockstore.internal;
|
||||
|
||||
import com.google.android.gms.common.api.Status;
|
||||
|
||||
interface IIsEndToEndEncryptionAvailableCallback {
|
||||
void onCheckEndToEndEncryptionResult(in Status status, boolean available);
|
||||
}
|
||||
|
|
@ -0,0 +1,14 @@
|
|||
/*
|
||||
* SPDX-FileCopyrightText: 2025 microG Project Team
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
package com.google.android.gms.auth.blockstore.internal;
|
||||
|
||||
import com.google.android.gms.common.api.Status;
|
||||
import com.google.android.gms.auth.blockstore.RetrieveBytesResponse;
|
||||
|
||||
interface IRetrieveBytesCallback {
|
||||
void onBytesResult(in Status status, in byte[] data);
|
||||
void onResponseResult(in Status status, in RetrieveBytesResponse response);
|
||||
}
|
||||
|
|
@ -0,0 +1,12 @@
|
|||
/*
|
||||
* SPDX-FileCopyrightText: 2025 microG Project Team
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
package com.google.android.gms.auth.blockstore.internal;
|
||||
|
||||
import com.google.android.gms.common.api.Status;
|
||||
|
||||
interface ISetBlockstoreDataCallback {
|
||||
void onSetBytesResult(in Status status, int storedSize);
|
||||
}
|
||||
|
|
@ -0,0 +1,12 @@
|
|||
/*
|
||||
* SPDX-FileCopyrightText: 2025 microG Project Team
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
package com.google.android.gms.auth.blockstore.internal;
|
||||
|
||||
import com.google.android.gms.common.api.Status;
|
||||
|
||||
interface IStoreBytesCallback {
|
||||
void onStoreBytesResult(in Status status, int result);
|
||||
}
|
||||
|
|
@ -0,0 +1,46 @@
|
|||
/*
|
||||
* SPDX-FileCopyrightText: 2025 microG Project Team
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
package com.google.android.gms.auth.blockstore;
|
||||
|
||||
import android.os.Parcel;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
import com.google.android.gms.common.internal.safeparcel.AbstractSafeParcelable;
|
||||
import com.google.android.gms.common.internal.safeparcel.SafeParcelable;
|
||||
import com.google.android.gms.common.internal.safeparcel.SafeParcelableCreatorAndWriter;
|
||||
|
||||
import org.microg.gms.common.Hide;
|
||||
import org.microg.gms.utils.ToStringHelper;
|
||||
|
||||
@SafeParcelable.Class
|
||||
@Hide
|
||||
public class AppRestoreInfo extends AbstractSafeParcelable {
|
||||
@Field(value = 1)
|
||||
public String restoreSessionId;
|
||||
|
||||
@Field(value = 2)
|
||||
public String restoreSource;
|
||||
|
||||
@Constructor
|
||||
public AppRestoreInfo(@Param(1) String restoreSessionId, @Param(2) String restoreSource) {
|
||||
this.restoreSessionId = restoreSessionId;
|
||||
this.restoreSource = restoreSource;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeToParcel(@NonNull Parcel dest, int flags) {
|
||||
CREATOR.writeToParcel(this, dest, flags);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public String toString() {
|
||||
return ToStringHelper.name("AppRestoreInfo").field("restoreSessionId", restoreSessionId).field("restoreSource", restoreSource).end();
|
||||
}
|
||||
|
||||
public static final SafeParcelableCreatorAndWriter<AppRestoreInfo> CREATOR = findCreator(AppRestoreInfo.class);
|
||||
}
|
||||
|
|
@ -0,0 +1,26 @@
|
|||
/*
|
||||
* SPDX-FileCopyrightText: 2025 microG Project Team
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
* Notice: Portions of this file are reproduced from work created and shared by Google and used
|
||||
* according to terms described in the Creative Commons 4.0 Attribution License.
|
||||
* See https://developers.google.com/readme/policies for details.
|
||||
*/
|
||||
|
||||
package com.google.android.gms.auth.blockstore;
|
||||
|
||||
import android.content.Context;
|
||||
|
||||
/**
|
||||
* Entry point for Block Store API.
|
||||
* <p>
|
||||
* Allows apps to transfer small amounts of data via device-to-device restore. This enables a seamless sign-in when users start using a new
|
||||
* device.
|
||||
*/
|
||||
public class Blockstore {
|
||||
/**
|
||||
* Creates a new instance of {@link BlockstoreClient}.
|
||||
*/
|
||||
public static BlockstoreClient getClient(Context context) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,119 @@
|
|||
/*
|
||||
* SPDX-FileCopyrightText: 2025 microG Project Team
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
* Notice: Portions of this file are reproduced from work created and shared by Google and used
|
||||
* according to terms described in the Creative Commons 4.0 Attribution License.
|
||||
* See https://developers.google.com/readme/policies for details.
|
||||
*/
|
||||
|
||||
package com.google.android.gms.auth.blockstore;
|
||||
|
||||
import com.google.android.gms.common.api.Api;
|
||||
import com.google.android.gms.common.api.HasApiKey;
|
||||
import com.google.android.gms.tasks.Task;
|
||||
|
||||
/**
|
||||
* The interface for clients to access Block Store.
|
||||
* <ul>
|
||||
* <li>
|
||||
* Clients should call storeBytes(StoreBytesData) to store authentication credentials byte[] bytes to enable seamless sign-in on
|
||||
* other devices.
|
||||
* </li>
|
||||
* <li>Clients should call retrieveBytes() to fetch the authentication credentials to seamlessly sign in users on a newly setup device.</li>
|
||||
* </ul>
|
||||
*/
|
||||
public interface BlockstoreClient extends HasApiKey<Api.ApiOptions.NoOptions> {
|
||||
/**
|
||||
* The default key with which the bytes are associated when {@link #storeBytes(StoreBytesData)} is called without explicitly setting a {@code key}.
|
||||
*/
|
||||
String DEFAULT_BYTES_DATA_KEY = "com.google.android.gms.auth.blockstore.DEFAULT_BYTES_DATA_KEY";
|
||||
|
||||
/**
|
||||
* Maximum number of distinct data entries, differentiated by the data keys, that can be stored using {@link BlockstoreClient#storeBytes(StoreBytesData)}.
|
||||
* <p>
|
||||
* The data key is the value provided when storing the data via {@link #storeBytes(StoreBytesData)}, as {@code StoreBytesData.key}.
|
||||
*/
|
||||
int MAX_ENTRY_COUNT = 16;
|
||||
|
||||
/**
|
||||
* Maximum allowed size of byte blobs that can be stored using {@link BlockstoreClient#storeBytes(StoreBytesData)}.
|
||||
*/
|
||||
int MAX_SIZE = 1024;
|
||||
|
||||
/**
|
||||
* Returns a {@link Task} which asynchronously deletes the bytes matching the filter(s) specified in {@code deleteBytesRequest}, with a Boolean result
|
||||
* representing whether any bytes were actually deleted.
|
||||
* <p>
|
||||
* If no bytes were found to delete, the task succeeds with a {@code false} return value.
|
||||
*
|
||||
* @throws NullPointerException if {@code deleteBytesRequest} is null.
|
||||
*/
|
||||
Task<Boolean> deleteBytes(DeleteBytesRequest deleteBytesRequest) throws NullPointerException;
|
||||
|
||||
/**
|
||||
* Returns a {@code Task} which asynchronously determines whether Block Store data backed up to the cloud will be end-to-end encrypted.
|
||||
* <p>
|
||||
* End-to-end encryption is available for Pie and above devices with a lockscreen PIN/pattern.
|
||||
* <p>
|
||||
* The {@code Boolean} return value is whether Block Store data backed up to the cloud will be end-to-end encrypted.
|
||||
*/
|
||||
Task<Boolean> isEndToEndEncryptionAvailable();
|
||||
|
||||
/**
|
||||
* Returns a {@code Task} which asynchronously retrieves the previously-stored bytes, if any, matching the filter(s) specified in
|
||||
* {@code retrieveBytesRequest}.
|
||||
* <p>
|
||||
* The returned {@code RetrieveBytesResponse} contains a map from data keys to {@code BlockstoreData}. The data may have been written on the same
|
||||
* device or may have been transferred during the device setup.
|
||||
* <p>
|
||||
* Use this API to seamlessly sign-in users to the apps on a new device.
|
||||
* <p>
|
||||
* If no data is found, returns an empty data map. Note that the data may be cleared by Google Play services on certain user actions, like user
|
||||
* clearing app storage (among others).
|
||||
* <p>
|
||||
* The bytes stored without an explicitly specified {@code StoreBytesData.key} can be requested with, and is returned associated with, the default
|
||||
* key {@link #DEFAULT_BYTES_DATA_KEY}.
|
||||
*
|
||||
* @throws NullPointerException if {@code retrieveBytesRequest} is null.
|
||||
*/
|
||||
Task<RetrieveBytesResponse> retrieveBytes(RetrieveBytesRequest retrieveBytesRequest) throws NullPointerException;
|
||||
|
||||
/**
|
||||
* Returns a {@link Task} which asynchronously retrieves the previously-stored bytes that was stored without an explicitly specified
|
||||
* {@code StoreBytesData.key}, if any. The maximum size of the {@code byte[]} is the {@link #MAX_SIZE}.
|
||||
* <p>
|
||||
* The {@code byte[]} may have been written on the same device or may have been transferred during the device setup.
|
||||
* <p>
|
||||
* Use this API to seamlessly sign-in users to the apps on a new device.
|
||||
* <p>
|
||||
* If no data is found, returns an empty byte array. Note that the data may be cleared by Google Play services on certain user actions, like user
|
||||
* clearing app storage (among others).
|
||||
*
|
||||
* @deprecated Use {@link #retrieveBytes(RetrieveBytesRequest)} instead.
|
||||
*/
|
||||
@Deprecated
|
||||
Task<byte[]> retrieveBytes();
|
||||
|
||||
/**
|
||||
* Returns a {@link Task} which asynchronously stores the provided {@code byte[] bytes} and associates it with the provided {@code String key}.
|
||||
* <p>
|
||||
* If the {@code key} is not explicitly set, then the {@code bytes} will be associated with the default key {@link #DEFAULT_BYTES_DATA_KEY}.
|
||||
* <p>
|
||||
* The data is stored locally. It is transferred to a new device during the device-to-device restore if a google account is also transferred.
|
||||
* <p>
|
||||
* If in {@link StoreBytesData#shouldBackupToCloud()} is set to {@code true}, the data will also be backed up to the cloud in the next periodic sync.
|
||||
* Cloud backup data is transferred to a new device during the cloud restore using Google's Backup & Restore services.
|
||||
* <p>
|
||||
* The maximum size of {@code String key} and {@code byte[] bytes} combined is {@link #MAX_SIZE}; otherwise, the API fails with
|
||||
* {@link BlockstoreStatusCodes#MAX_SIZE_EXCEEDED} error code.
|
||||
* <p>
|
||||
* The maximum number of data entries allowed is {@link #MAX_ENTRY_COUNT}; otherwise, the API fails with
|
||||
* {@link BlockstoreStatusCodes#TOO_MANY_ENTRIES} error code.
|
||||
* <p>
|
||||
* The {@code Integer} return value is the size of {@code byte[] bytes} successfully stored.
|
||||
* <p>
|
||||
* Use this API to store small data blobs that can enable seamless sign in for your apps. The API may be called periodically (for example, a few
|
||||
* times per day) to refresh the data blob. Successive calls with the same key to this API will overwrite the existing bytes.
|
||||
*/
|
||||
Task<Integer> storeBytes(StoreBytesData storeBytesData);
|
||||
}
|
||||
|
|
@ -0,0 +1,35 @@
|
|||
/*
|
||||
* SPDX-FileCopyrightText: 2025 microG Project Team
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
* Notice: Portions of this file are reproduced from work created and shared by Google and used
|
||||
* according to terms described in the Creative Commons 4.0 Attribution License.
|
||||
* See https://developers.google.com/readme/policies for details.
|
||||
*/
|
||||
|
||||
package com.google.android.gms.auth.blockstore;
|
||||
|
||||
import com.google.android.gms.common.api.CommonStatusCodes;
|
||||
|
||||
/**
|
||||
* Block Store specific status codes.
|
||||
* <p>
|
||||
* Codes are allocated from the range 40000 to 40499, allocated in {@link CommonStatusCodes}.
|
||||
*/
|
||||
public class BlockstoreStatusCodes extends CommonStatusCodes {
|
||||
|
||||
/**
|
||||
* The available quota was exceeded.
|
||||
*/
|
||||
public static final int MAX_SIZE_EXCEEDED = 40000;
|
||||
|
||||
/**
|
||||
* Attempting to store a new key value pair after reaching the maximum number of entries allowed.
|
||||
*/
|
||||
public static final int TOO_MANY_ENTRIES = 40001;
|
||||
|
||||
/**
|
||||
* Attempting to use a Blockstore feature that is not (yet) supported on the given device.
|
||||
*/
|
||||
public static final int FEATURE_NOT_SUPPORTED = 40002;
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,138 @@
|
|||
/*
|
||||
* SPDX-FileCopyrightText: 2025 microG Project Team
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
* Notice: Portions of this file are reproduced from work created and shared by Google and used
|
||||
* according to terms described in the Creative Commons 4.0 Attribution License.
|
||||
* See https://developers.google.com/readme/policies for details.
|
||||
*/
|
||||
|
||||
package com.google.android.gms.auth.blockstore;
|
||||
|
||||
import android.os.Parcel;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
import com.google.android.gms.common.internal.safeparcel.AbstractSafeParcelable;
|
||||
import com.google.android.gms.common.internal.safeparcel.SafeParcelable;
|
||||
import com.google.android.gms.common.internal.safeparcel.SafeParcelableCreatorAndWriter;
|
||||
|
||||
import org.microg.gms.common.Hide;
|
||||
import org.microg.gms.utils.ToStringHelper;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* A request to delete app data from BlockStore.
|
||||
*/
|
||||
@SafeParcelable.Class
|
||||
public class DeleteBytesRequest extends AbstractSafeParcelable {
|
||||
|
||||
@Field(value = 1, getterName = "getKeys")
|
||||
private final List<String> keys;
|
||||
|
||||
@Field(value = 2, getterName = "getDeleteAll")
|
||||
private final boolean deleteAll;
|
||||
|
||||
@Constructor
|
||||
DeleteBytesRequest(@Param(1) List<String> keys, @Param(2) boolean deleteAll) {
|
||||
this.keys = keys;
|
||||
this.deleteAll = deleteAll;
|
||||
if (deleteAll && keys != null && !keys.isEmpty()) {
|
||||
throw new IllegalArgumentException("deleteAll was set to true but keys were also provided");
|
||||
}
|
||||
for (String key : keys) {
|
||||
if (key == null || key.isEmpty()) {
|
||||
throw new IllegalArgumentException("Element in keys cannot be null or empty");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the list of keys whose associated data, if any, should be deleted.
|
||||
* <p>
|
||||
* An empty list means that no key-based filtering will be performed. In other words, no data will be deleted if the key list is empty and no other
|
||||
* criterion is provided.
|
||||
* <p>
|
||||
* Note that the app data that was stored without an explicit key can be deleted with the default key
|
||||
* {@link BlockstoreClient#DEFAULT_BYTES_DATA_KEY}.
|
||||
*/
|
||||
@NonNull
|
||||
public List<String> getKeys() {
|
||||
return keys;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether or not all app's Block Store data should be deleted.
|
||||
*/
|
||||
public boolean getDeleteAll() {
|
||||
return deleteAll;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeToParcel(@NonNull Parcel dest, int flags) {
|
||||
CREATOR.writeToParcel(this, dest, flags);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
@Hide
|
||||
public String toString() {
|
||||
return ToStringHelper.name("DeleteBytesRequest").field("deleteAll", deleteAll).field("keys", keys).end();
|
||||
}
|
||||
|
||||
public static final SafeParcelableCreatorAndWriter<DeleteBytesRequest> CREATOR = findCreator(DeleteBytesRequest.class);
|
||||
|
||||
/**
|
||||
* A builder for {@link DeleteBytesRequest} objects.
|
||||
*/
|
||||
public static class Builder {
|
||||
private final List<String> keyList = new ArrayList<>();
|
||||
private boolean deleteAll = false;
|
||||
|
||||
/**
|
||||
* Constructor for the {@link DeleteBytesRequest.Builder} class.
|
||||
*/
|
||||
public Builder() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds and returns the {@link DeleteBytesRequest} object.
|
||||
*/
|
||||
public DeleteBytesRequest build() {
|
||||
if (deleteAll && !keyList.isEmpty()) {
|
||||
throw new IllegalStateException("deleteAll=true but keys are provided");
|
||||
}
|
||||
return new DeleteBytesRequest(new ArrayList<>(keyList), deleteAll);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets whether or not all app's Block Store data should be deleted.
|
||||
* <p>
|
||||
* The default is {@code false}.
|
||||
* <p>
|
||||
* Note that if {@code deleteAll} is set to true, then you should NOT set any other deletion criterion, e.g. {@code keys} should be empty. Otherwise, an
|
||||
* IllegalStateException will be thrown.
|
||||
*/
|
||||
public Builder setDeleteAll(boolean deleteAll) {
|
||||
this.deleteAll = deleteAll;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the list of keys whose associated data, if any, should be deleted.
|
||||
* <p>
|
||||
* The default value is an empty list, which means that no key-based filtering will be performed. In other words, no data will be deleted if the
|
||||
* key list is empty and no other criterion is provided.
|
||||
* <p>
|
||||
* Note that the app data that was stored without an explicit key can be deleted with the default key
|
||||
* {@link BlockstoreClient#DEFAULT_BYTES_DATA_KEY}.
|
||||
*/
|
||||
public Builder setKeys(List<String> keys) {
|
||||
keyList.clear();
|
||||
keyList.addAll(keys);
|
||||
return this;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,132 @@
|
|||
/*
|
||||
* SPDX-FileCopyrightText: 2025 microG Project Team
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
* Notice: Portions of this file are reproduced from work created and shared by Google and used
|
||||
* according to terms described in the Creative Commons 4.0 Attribution License.
|
||||
* See https://developers.google.com/readme/policies for details.
|
||||
*/
|
||||
|
||||
package com.google.android.gms.auth.blockstore;
|
||||
|
||||
import android.os.Parcel;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
import com.google.android.gms.common.internal.safeparcel.AbstractSafeParcelable;
|
||||
import com.google.android.gms.common.internal.safeparcel.SafeParcelable;
|
||||
import com.google.android.gms.common.internal.safeparcel.SafeParcelableCreatorAndWriter;
|
||||
|
||||
import org.microg.gms.common.PublicApi;
|
||||
import org.microg.gms.utils.ToStringHelper;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* A request to retrieve app data from BlockStore.
|
||||
*/
|
||||
@SafeParcelable.Class
|
||||
public class RetrieveBytesRequest extends AbstractSafeParcelable {
|
||||
|
||||
@Field(value = 1, getterName = "getKeys")
|
||||
private final List<String> keys;
|
||||
|
||||
@Field(value = 2, getterName = "getRetrieveAll")
|
||||
private final boolean retrieveAll;
|
||||
|
||||
@Constructor
|
||||
RetrieveBytesRequest(@Param(1) List<String> keys, @Param(2) boolean retrieveAll) {
|
||||
if (retrieveAll && keys != null && !keys.isEmpty()) {
|
||||
throw new IllegalArgumentException("retrieveAll was set to true but other constraint(s) was also provided: keys");
|
||||
}
|
||||
this.retrieveAll = retrieveAll;
|
||||
|
||||
List<String> tmp = new ArrayList<>();
|
||||
if (keys != null) {
|
||||
for (String k : keys) {
|
||||
if (k == null || k.isEmpty()) {
|
||||
throw new IllegalArgumentException("Element in keys cannot be null or empty");
|
||||
}
|
||||
tmp.add(k);
|
||||
}
|
||||
}
|
||||
this.keys = Collections.unmodifiableList(tmp);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the list of keys whose associated data, if any, should be retrieved.
|
||||
* <p>
|
||||
* An empty list means that no key-based filtering will be performed. In other words, no data will be returned if the key list is empty and no
|
||||
* other criterion is provided.
|
||||
* <p>
|
||||
* Note that the app data that was stored without an explicit key can be requested with the default key
|
||||
* {@link BlockstoreClient#DEFAULT_BYTES_DATA_KEY}.
|
||||
*/
|
||||
public List<String> getKeys() {
|
||||
return keys;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether or not all app's Block Store data should be retrieved.
|
||||
*/
|
||||
public boolean getRetrieveAll() {
|
||||
return retrieveAll;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeToParcel(@NonNull Parcel dest, int flags) {
|
||||
CREATOR.writeToParcel(this, dest, flags);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return ToStringHelper.name("RetrieveBytesRequest").field("keys", keys).field("retrieveAll", retrieveAll).end();
|
||||
}
|
||||
|
||||
public static final SafeParcelableCreatorAndWriter<RetrieveBytesRequest> CREATOR = findCreator(RetrieveBytesRequest.class);
|
||||
|
||||
/**
|
||||
* A builder for {@link RetrieveBytesRequest} objects.
|
||||
*/
|
||||
public static class Builder {
|
||||
private final List<String> keys = new ArrayList<>();
|
||||
private boolean retrieveAll = false;
|
||||
|
||||
/**
|
||||
* Builds and returns the {@link RetrieveBytesRequest} object.
|
||||
*/
|
||||
@NonNull
|
||||
public RetrieveBytesRequest build() {
|
||||
return new RetrieveBytesRequest(new ArrayList<>(keys), retrieveAll);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the list of keys whose associated data, if any, should be retrieved.
|
||||
* <p>
|
||||
* The default value is an empty list, which means that no key-based filtering will be performed. In other words, no data will be returned if the
|
||||
* key list is empty and no other criterion is provided.
|
||||
* <p>
|
||||
* Note that the app data that was stored without an explicit key can be requested with the default key
|
||||
* {@link BlockstoreClient#DEFAULT_BYTES_DATA_KEY}.
|
||||
*/
|
||||
public Builder setKeys(List<String> keys) {
|
||||
this.keys.clear();
|
||||
this.keys.addAll(keys);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets whether or not all app's Block Store data should be retrieved.
|
||||
* <p>
|
||||
* The default is {@code false}.
|
||||
* <p>
|
||||
* Note that if {@code retrieveAll} is set to true, then you should NOT set any other retrieval criterion, e.g. {@code keys} should be empty. Otherwise, an
|
||||
* IllegalStateException will be thrown.
|
||||
*/
|
||||
public Builder retrieveAll(boolean retrieveAll) {
|
||||
this.retrieveAll = retrieveAll;
|
||||
return this;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,139 @@
|
|||
/*
|
||||
* SPDX-FileCopyrightText: 2025 microG Project Team
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
* Notice: Portions of this file are reproduced from work created and shared by Google and used
|
||||
* according to terms described in the Creative Commons 4.0 Attribution License.
|
||||
* See https://developers.google.com/readme/policies for details.
|
||||
*/
|
||||
|
||||
package com.google.android.gms.auth.blockstore;
|
||||
|
||||
import android.os.Bundle;
|
||||
import android.os.Parcel;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
import com.google.android.gms.common.internal.safeparcel.AbstractSafeParcelable;
|
||||
import com.google.android.gms.common.internal.safeparcel.SafeParcelable;
|
||||
import com.google.android.gms.common.internal.safeparcel.SafeParcelableCreatorAndWriter;
|
||||
|
||||
import org.microg.gms.common.Hide;
|
||||
import org.microg.gms.utils.ToStringHelper;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* App data retrieved from BlockStore.
|
||||
*/
|
||||
@SafeParcelable.Class
|
||||
public class RetrieveBytesResponse extends AbstractSafeParcelable {
|
||||
|
||||
@Deprecated
|
||||
@Field(value = 1, getterName = "getInternalBlockstoreDataBundle")
|
||||
private final Bundle internalBlockstoreDataBundle;
|
||||
|
||||
@Field(value = 2, getterName = "getInternalBlockstoreDataList")
|
||||
private final List<BlockstoreData> internalBlockstoreDataList;
|
||||
|
||||
private final Map<String, BlockstoreData> blockstoreDataMap;
|
||||
|
||||
@Constructor
|
||||
@Hide
|
||||
public RetrieveBytesResponse(@Param(1) Bundle internalBlockstoreDataBundle, @Param(2) List<BlockstoreData> internalBlockstoreDataList) {
|
||||
this.internalBlockstoreDataBundle = internalBlockstoreDataBundle;
|
||||
this.internalBlockstoreDataList = internalBlockstoreDataList;
|
||||
HashMap<String, BlockstoreData> blockstoreDataMap = new HashMap<>();
|
||||
for (BlockstoreData blockstoreData : internalBlockstoreDataList) {
|
||||
blockstoreDataMap.put(blockstoreData.key, blockstoreData);
|
||||
}
|
||||
this.blockstoreDataMap = blockstoreDataMap;
|
||||
}
|
||||
|
||||
/**
|
||||
* A mapping from app data key to {@link RetrieveBytesResponse.BlockstoreData} found based on a {@link RetrieveBytesRequest}.
|
||||
* <p>
|
||||
* The app data key is the value provided when storing the data via {@link BlockstoreClient#storeBytes(StoreBytesData)}, as
|
||||
* {@code StoreBytesData.key}.
|
||||
* <p>
|
||||
* Note that the app data that was stored without an explicit key is associated with the default key
|
||||
* {@link BlockstoreClient#DEFAULT_BYTES_DATA_KEY}.
|
||||
*/
|
||||
public Map<String, RetrieveBytesResponse.BlockstoreData> getBlockstoreDataMap() {
|
||||
return blockstoreDataMap;
|
||||
}
|
||||
|
||||
@Hide
|
||||
public Bundle getInternalBlockstoreDataBundle() {
|
||||
return internalBlockstoreDataBundle;
|
||||
}
|
||||
|
||||
@Hide
|
||||
public List<BlockstoreData> getInternalBlockstoreDataList() {
|
||||
return internalBlockstoreDataList;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeToParcel(@NonNull Parcel dest, int flags) {
|
||||
CREATOR.writeToParcel(this, dest, flags);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
@Hide
|
||||
public String toString() {
|
||||
return ToStringHelper.name("RetrieveBytesResponse").value(blockstoreDataMap).end();
|
||||
}
|
||||
|
||||
public static final SafeParcelableCreatorAndWriter<RetrieveBytesResponse> CREATOR = findCreator(RetrieveBytesResponse.class);
|
||||
|
||||
/**
|
||||
* A block of app data previously stored to Block Store.
|
||||
*/
|
||||
@SafeParcelable.Class
|
||||
public static class BlockstoreData extends AbstractSafeParcelable {
|
||||
@Field(value = 1, getterName = "getBytes")
|
||||
@NonNull
|
||||
private final byte[] bytes;
|
||||
|
||||
@Field(value = 2, getterName = "getKey")
|
||||
@NonNull
|
||||
private final String key;
|
||||
|
||||
@Constructor
|
||||
@Hide
|
||||
public BlockstoreData(@NonNull @Param(1) byte[] bytes, @NonNull @Param(2) String key) {
|
||||
this.bytes = bytes;
|
||||
this.key = key;
|
||||
}
|
||||
|
||||
/**
|
||||
* Raw bytes passed from the app to Block Store.
|
||||
*/
|
||||
@NonNull
|
||||
public byte[] getBytes() {
|
||||
return bytes;
|
||||
}
|
||||
|
||||
@Hide
|
||||
@NonNull
|
||||
public String getKey() {
|
||||
return key;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
@Hide
|
||||
public String toString() {
|
||||
return ToStringHelper.name("BlockstoreData").value(key).field("bytes", bytes, true).end();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeToParcel(@NonNull Parcel dest, int flags) {
|
||||
CREATOR.writeToParcel(this, dest, flags);
|
||||
}
|
||||
|
||||
public static final SafeParcelableCreatorAndWriter<BlockstoreData> CREATOR = findCreator(BlockstoreData.class);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,134 @@
|
|||
/*
|
||||
* SPDX-FileCopyrightText: 2025 microG Project Team
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
* Notice: Portions of this file are reproduced from work created and shared by Google and used
|
||||
* according to terms described in the Creative Commons 4.0 Attribution License.
|
||||
* See https://developers.google.com/readme/policies for details.
|
||||
*/
|
||||
|
||||
package com.google.android.gms.auth.blockstore;
|
||||
|
||||
import android.os.Parcel;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
import com.google.android.gms.common.internal.safeparcel.AbstractSafeParcelable;
|
||||
import com.google.android.gms.common.internal.safeparcel.SafeParcelable;
|
||||
import com.google.android.gms.common.internal.safeparcel.SafeParcelableCreatorAndWriter;
|
||||
|
||||
import org.microg.gms.common.Hide;
|
||||
import org.microg.gms.utils.ToStringHelper;
|
||||
|
||||
/**
|
||||
* Data passed by apps to Block Store.
|
||||
*/
|
||||
@SafeParcelable.Class
|
||||
public class StoreBytesData extends AbstractSafeParcelable {
|
||||
|
||||
@Field(value = 1, getterName = "getBytes")
|
||||
@NonNull
|
||||
private final byte[] bytes;
|
||||
|
||||
@Field(value = 2, getterName = "shouldBackupToCloud")
|
||||
private final boolean shouldBackupToCloud;
|
||||
|
||||
@Field(value = 3, getterName = "getKey")
|
||||
private final String key;
|
||||
|
||||
@Constructor
|
||||
StoreBytesData(@NonNull @Param(1) byte[] bytes, @Param(2) boolean shouldBackupToCloud, @Param(3) String key) {
|
||||
this.bytes = bytes;
|
||||
this.shouldBackupToCloud = shouldBackupToCloud;
|
||||
this.key = key;
|
||||
}
|
||||
|
||||
/**
|
||||
* Raw bytes passed from apps to Block Store.
|
||||
*/
|
||||
@NonNull
|
||||
public byte[] getBytes() {
|
||||
return bytes;
|
||||
}
|
||||
|
||||
/**
|
||||
* The key with which the bytes are associated.
|
||||
* <p>
|
||||
* If the key was never explicitly set when building the {@code StoreBytesData}, then the default key {@link BlockstoreClient#DEFAULT_BYTES_DATA_KEY}
|
||||
* is associated with the {@code bytes} and therefore will be returned.
|
||||
*/
|
||||
@NonNull
|
||||
public String getKey() {
|
||||
return key;
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether the bytes to be stored should be backed up to the cloud in the next sync.
|
||||
*/
|
||||
public boolean shouldBackupToCloud() {
|
||||
return shouldBackupToCloud;
|
||||
}
|
||||
|
||||
public static final SafeParcelableCreatorAndWriter<StoreBytesData> CREATOR = findCreator(StoreBytesData.class);
|
||||
|
||||
@Override
|
||||
public void writeToParcel(@NonNull Parcel dest, int flags) {
|
||||
CREATOR.writeToParcel(this, dest, flags);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
@Hide
|
||||
public String toString() {
|
||||
return ToStringHelper.name("StoreBytesData").field("bytes", bytes != null ? bytes.length : 0).field("shouldBackupToCloud", shouldBackupToCloud).field("key", key).end();
|
||||
}
|
||||
|
||||
/**
|
||||
* A builder for {@link StoreBytesData} objects.
|
||||
*/
|
||||
public static class Builder {
|
||||
private byte[] bytes;
|
||||
private boolean shouldBackupToCloud = false;
|
||||
private String key = BlockstoreClient.DEFAULT_BYTES_DATA_KEY;
|
||||
|
||||
/**
|
||||
* Constructor for the {@link StoreBytesData.Builder} class.
|
||||
*/
|
||||
public Builder() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds and returns the {@link StoreBytesData} object.
|
||||
*/
|
||||
public StoreBytesData build() {
|
||||
return new StoreBytesData(bytes, shouldBackupToCloud, key);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the raw bytes to be stored with Block Store. See {@link BlockstoreClient#MAX_SIZE} for the maximum size allowed for a key-bytes entry.
|
||||
*/
|
||||
public Builder setBytes(byte[] bytes) {
|
||||
this.bytes = bytes;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the key with which the {@code bytes} are associated with. See {@link BlockstoreClient#MAX_SIZE} for the maximum size allowed for a key-bytes
|
||||
* entry.
|
||||
* <p>
|
||||
* If {@code setKey} is never invoked, the bytes will be associated with the default key {@link BlockstoreClient#DEFAULT_BYTES_DATA_KEY} when stored
|
||||
* into Block Store.
|
||||
*/
|
||||
public Builder setKey(String key) {
|
||||
this.key = key;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets whether the bytes to be stored should be backed up to the cloud in the next sync.
|
||||
*/
|
||||
public Builder setShouldBackupToCloud(boolean shouldBackupToCloud) {
|
||||
this.shouldBackupToCloud = shouldBackupToCloud;
|
||||
return this;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
/*
|
||||
* SPDX-FileCopyrightText: 2022 microG Project Team
|
||||
* SPDX-License-Identifier: CC-BY-4.0
|
||||
* Notice: Portions of this file are reproduced from work created and shared by Google and used
|
||||
* according to terms described in the Creative Commons 4.0 Attribution License.
|
||||
* See https://developers.google.com/readme/policies for details.
|
||||
*/
|
||||
/**
|
||||
* Contains the Block Store API.
|
||||
*/
|
||||
package com.google.android.gms.auth.blockstore;
|
||||
Loading…
Add table
Add a link
Reference in a new issue