Identity: Add IdentityCredentialApiService dummy (#3484)

Co-authored-by: Marvin W <git@larma.de>
This commit is contained in:
DaVinci9196 2026-06-30 05:42:31 +08:00 committed by GitHub
parent 67c1bb7501
commit 4e8200a1ea
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
89 changed files with 4117 additions and 61 deletions

View file

@ -73,7 +73,7 @@ def execResult(... args) {
}
def ignoreGit = providers.environmentVariable('GRADLE_MICROG_VERSION_WITHOUT_GIT').getOrElse('0') == '1'
def gmsVersion = "25.09.32"
def gmsVersion = "25.24.32"
def gmsVersionCode = Integer.parseInt(gmsVersion.replaceAll('\\.', ''))
def vendingVersion = "40.2.26"
def vendingVersionCode = Integer.parseInt(vendingVersion.replaceAll('\\.', ''))

View file

@ -370,7 +370,7 @@ public enum GmsService {
GOOGLESETTINGS(349),
HTTPFLAGS(350),
SETUP_SERVICES_REMOTE_SETUP(351),
IDENTITY_CREDENTIALS(352),
IDENTITY_CREDENTIALS(352, "com.google.android.gms.identitycredentials.service.START"),
AMBIENT_CONTEXT(353),
SAFE_BROWSING(354),
MULTIDEVICE_API_FEATURE_SETTINGS(355),

View file

@ -37,6 +37,7 @@ dependencies {
implementation project(':play-services-fido-core')
implementation project(':play-services-fitness-core')
implementation project(':play-services-gmscompliance-core')
implementation project(':play-services-identity-credentials-core')
implementation project(':play-services-location-core')
implementation project(':play-services-location-core-base')
implementation project(':play-services-oss-licenses-core')

View file

@ -649,6 +649,13 @@
android:theme="@style/Theme.App.Translucent"
android:excludeFromRecents="true"/>
<activity
android:name="org.microg.gms.auth.credentials.identity.IdentityCredentialChooserActivity"
android:exported="false"
android:process=":ui"
android:theme="@style/Theme.App.Translucent"
android:excludeFromRecents="true"/>
<activity
android:theme="@style/Theme.AppCompat.Dialog.Alert"
android:name="org.microg.gms.auth.signin.AssistedSignInActivity"

View file

@ -0,0 +1,50 @@
/*
* SPDX-FileCopyrightText: 2026 microG Project Team
* SPDX-License-Identifier: Apache-2.0
*/
package org.microg.gms.auth.credentials
import android.content.Context
import android.content.Intent
import com.google.android.gms.auth.api.signin.GoogleSignInOptions
import com.google.android.gms.common.internal.safeparcel.SafeParcelableSerializer
import org.microg.gms.auth.signin.ACTION_ASSISTED_SIGN_IN
import org.microg.gms.auth.signin.CLIENT_PACKAGE_NAME
import org.microg.gms.auth.signin.GOOGLE_SIGN_IN_OPTIONS
import org.microg.gms.common.GmsService
import org.microg.gms.fido.core.ui.ACTION_FIDO_AUTHENTICATE
import org.microg.gms.fido.core.ui.AuthenticatorActivity.Companion.KEY_CALLER
import org.microg.gms.fido.core.ui.AuthenticatorActivity.Companion.KEY_CREDENTIAL_ID
import org.microg.gms.fido.core.ui.AuthenticatorActivity.Companion.KEY_OPTIONS
import org.microg.gms.fido.core.ui.AuthenticatorActivity.Companion.KEY_SERVICE
import org.microg.gms.fido.core.ui.AuthenticatorActivity.Companion.KEY_SOURCE
import org.microg.gms.fido.core.ui.AuthenticatorActivity.Companion.KEY_TYPE
fun Context.buildFidoAuthenticateIntent(
source: String,
optionsBytes: ByteArray,
callingPackage: String?,
type: String,
credentialIdString: String? = null,
): Intent = Intent(ACTION_FIDO_AUTHENTICATE).apply {
`package` = packageName
putExtra(KEY_SERVICE, GmsService.FIDO2_API.SERVICE_ID)
putExtra(KEY_SOURCE, source)
putExtra(KEY_TYPE, type)
putExtra(KEY_OPTIONS, optionsBytes)
callingPackage?.let { putExtra(KEY_CALLER, it) }
credentialIdString?.let { putExtra(KEY_CREDENTIAL_ID, it) }
}
fun Context.buildAssistedSignInIntent(
requestExtraKey: String,
serializedRequest: ByteArray,
googleSignInOptions: GoogleSignInOptions,
callingPackage: String?,
): Intent = Intent(ACTION_ASSISTED_SIGN_IN).apply {
`package` = packageName
putExtra(requestExtraKey, serializedRequest)
putExtra(GOOGLE_SIGN_IN_OPTIONS, SafeParcelableSerializer.serializeToBytes(googleSignInOptions))
callingPackage?.let { putExtra(CLIENT_PACKAGE_NAME, it) }
}

View file

@ -0,0 +1,295 @@
/*
* SPDX-FileCopyrightText: 2026 microG Project Team
* SPDX-License-Identifier: Apache-2.0
*/
package org.microg.gms.auth.credentials.identity
import android.content.Intent
import android.os.Bundle
import android.os.Parcelable
import android.util.Log
import androidx.appcompat.app.AppCompatActivity
import androidx.core.os.BundleCompat
import androidx.credentials.PasswordCredential
import androidx.credentials.PublicKeyCredential
import androidx.credentials.exceptions.CreateCredentialNoCreateOptionException
import androidx.credentials.exceptions.CreateCredentialUnknownException
import androidx.credentials.exceptions.GetCredentialCancellationException
import androidx.credentials.exceptions.GetCredentialUnknownException
import androidx.credentials.exceptions.NoCredentialException
import com.google.android.gms.auth.api.identity.BeginSignInRequest
import com.google.android.gms.auth.api.identity.SignInCredential
import com.google.android.gms.auth.api.signin.GoogleSignInOptions
import com.google.android.gms.common.internal.safeparcel.SafeParcelableSerializer
import com.google.android.gms.fido.Fido.FIDO2_KEY_CREDENTIAL_EXTRA
import com.google.android.gms.fido.fido2.api.common.AuthenticatorErrorResponse
import com.google.android.gms.identitycredentials.CreateCredentialRequest
import com.google.android.gms.identitycredentials.CredentialOption
import com.google.android.gms.identitycredentials.GetCredentialRequest
import org.json.JSONObject
import org.microg.gms.auth.AuthConstants
import org.microg.gms.auth.credentials.buildAssistedSignInIntent
import org.microg.gms.auth.credentials.buildFidoAuthenticateIntent
import org.microg.gms.identitycredentials.EXTRA_CALLING_PACKAGE
import org.microg.gms.identitycredentials.EXTRA_CREATE_REQUEST
import org.microg.gms.identitycredentials.EXTRA_GET_REQUEST
import org.microg.gms.auth.credentials.provider.GOOGLE_ID_ANDROIDX_AUTO_SELECT
import org.microg.gms.auth.credentials.provider.GOOGLE_ID_BUNDLE_KEY_DISPLAY_NAME
import org.microg.gms.auth.credentials.provider.GOOGLE_ID_BUNDLE_KEY_FAMILY_NAME
import org.microg.gms.auth.credentials.provider.GOOGLE_ID_BUNDLE_KEY_GIVEN_NAME
import org.microg.gms.auth.credentials.provider.GOOGLE_ID_BUNDLE_KEY_ID
import org.microg.gms.auth.credentials.provider.GOOGLE_ID_BUNDLE_KEY_ID_TOKEN
import org.microg.gms.auth.credentials.provider.GOOGLE_ID_BUNDLE_KEY_PROFILE_PICTURE_URI
import org.microg.gms.auth.credentials.provider.GOOGLE_ID_FILTER_BY_AUTHORIZED_ACCOUNTS
import org.microg.gms.auth.credentials.provider.GOOGLE_ID_NONCE
import org.microg.gms.auth.credentials.provider.GOOGLE_ID_SERVER_CLIENT_ID
import org.microg.gms.auth.credentials.provider.GOOGLE_ID_SIWG_NONCE
import org.microg.gms.auth.credentials.provider.GOOGLE_ID_SIWG_SERVER_CLIENT_ID
import org.microg.gms.auth.credentials.provider.TYPE_GOOGLE_ID_TOKEN_CREDENTIAL
import org.microg.gms.auth.credentials.provider.parsePublicKeyCredentialCreationOptions
import org.microg.gms.auth.credentials.provider.parsePublicKeyCredentialRequestOptions
import org.microg.gms.auth.credentials.provider.toJson
import org.microg.gms.auth.signin.BEGIN_SIGN_IN_REQUEST
import org.microg.gms.fido.core.ui.AuthenticatorActivity.Companion.SOURCE_APP
import org.microg.gms.fido.core.ui.AuthenticatorActivity.Companion.TYPE_REGISTER
import org.microg.gms.fido.core.ui.AuthenticatorActivity.Companion.TYPE_SIGN
private const val TAG = "IdentityCredChooser"
class IdentityCredentialChooserActivity : AppCompatActivity() {
private var callingPackage: String = ""
private var isCreatePath = false
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
callingPackage = intent.getStringExtra(EXTRA_CALLING_PACKAGE).orEmpty()
runCatching {
val getReq: GetCredentialRequest? = readNestedParcelable(EXTRA_GET_REQUEST, GetCredentialRequest::class.java)
val createReq: CreateCredentialRequest? = readNestedParcelable(EXTRA_CREATE_REQUEST, CreateCredentialRequest::class.java)
when {
getReq != null -> {
isCreatePath = false
Log.d(TAG, "onCreate get pkg=$callingPackage options=${getReq.credentialOptions.size}")
routeGet(getReq)
}
createReq != null -> {
isCreatePath = true
Log.d(TAG, "onCreate create pkg=$callingPackage type=${createReq.type} origin=${createReq.origin}")
routeCreate(createReq)
}
else -> finishWithGetException(GetCredentialUnknownException("Missing request payload"))
}
}.onFailure { e ->
Log.e(TAG, "onCreate parse failed", e)
if (isCreatePath) finishWithCreateException(CreateCredentialUnknownException(e.message ?: "Internal error"))
else finishWithGetException(GetCredentialUnknownException(e.message ?: "Internal error"))
}
}
private fun routeGet(req: GetCredentialRequest) {
val option = req.credentialOptions.firstOrNull()
?: return finishWithGetException(NoCredentialException("No credential options requested"))
when (option.type) {
PublicKeyCredential.TYPE_PUBLIC_KEY_CREDENTIAL -> startPasskeyGet(option)
TYPE_GOOGLE_ID_TOKEN_CREDENTIAL -> startGoogleSignIn(option)
PasswordCredential.TYPE_PASSWORD_CREDENTIAL ->
finishWithGetException(NoCredentialException("Password credentials are not stored"))
else -> finishWithGetException(NoCredentialException("Unsupported type: ${option.type}"))
}
}
private fun routeCreate(req: CreateCredentialRequest) {
Log.d(TAG, "routeCreate type=${req.type} pkg=$callingPackage")
when (req.type) {
PublicKeyCredential.TYPE_PUBLIC_KEY_CREDENTIAL -> startPasskeyCreate(req)
else -> finishWithCreateException(CreateCredentialNoCreateOptionException("Unsupported create type: ${req.type}"))
}
}
private fun startPasskeyGet(option: CredentialOption) {
val data = option.credentialRetrievalData
val requestJson = data?.getString(PUBKEY_REQ_JSON_KEY)
?: return finishWithGetException(NoCredentialException("Passkey request missing requestJson"))
val pkOptions = runCatching {
JSONObject(requestJson).parsePublicKeyCredentialRequestOptions()
}.getOrElse {
Log.e(TAG, "Passkey JSON parse failed", it)
return finishWithGetException(GetCredentialUnknownException("Invalid passkey requestJson"))
}
val fidoIntent = buildFidoAuthenticateIntent(SOURCE_APP, pkOptions.serializeToBytes(), callingPackage, TYPE_SIGN)
startActivityForResult(fidoIntent, REQ_CODE_FIDO)
}
private fun startPasskeyCreate(req: CreateCredentialRequest) {
val requestJson = req.requestJson ?: req.credentialData.getString(PUBKEY_REQ_JSON_KEY)
if (requestJson.isNullOrBlank()) {
return finishWithCreateException(CreateCredentialUnknownException("Passkey create missing requestJson"))
}
val pkOptions = runCatching {
JSONObject(requestJson).parsePublicKeyCredentialCreationOptions()
}.getOrElse {
Log.e(TAG, "Passkey create JSON parse failed", it)
return finishWithCreateException(CreateCredentialUnknownException("Invalid passkey requestJson"))
}
val fidoIntent = buildFidoAuthenticateIntent(SOURCE_APP, pkOptions.serializeToBytes(), callingPackage, TYPE_REGISTER)
startActivityForResult(fidoIntent, REQ_CODE_FIDO)
}
private fun startGoogleSignIn(option: CredentialOption) {
val data = option.credentialRetrievalData ?: Bundle()
val serverClientId = (data.getString(GOOGLE_ID_SERVER_CLIENT_ID) ?: data.getString(GOOGLE_ID_SIWG_SERVER_CLIENT_ID)).orEmpty()
if (serverClientId.isBlank()) {
return finishWithGetException(NoCredentialException("GoogleIdToken option missing serverClientId"))
}
val nonce = data.getString(GOOGLE_ID_NONCE) ?: data.getString(GOOGLE_ID_SIWG_NONCE)
val filterByAuthorized = data.getBoolean(GOOGLE_ID_FILTER_BY_AUTHORIZED_ACCOUNTS, false)
val autoSelect = data.getBoolean(GOOGLE_ID_ANDROIDX_AUTO_SELECT, false)
val signInRequest = BeginSignInRequest.Builder()
.setGoogleIdTokenRequestOptions(
BeginSignInRequest.GoogleIdTokenRequestOptions.builder()
.setSupported(true)
.setServerClientId(serverClientId)
.setFilterByAuthorizedAccounts(filterByAuthorized)
.apply { nonce?.let { setNonce(it) } }
.build()
)
.setAutoSelectEnabled(autoSelect)
.build()
val gso = GoogleSignInOptions.Builder(GoogleSignInOptions.DEFAULT_SIGN_IN)
.requestEmail()
.requestIdToken(serverClientId)
.build()
val signInIntent = buildAssistedSignInIntent(
requestExtraKey = BEGIN_SIGN_IN_REQUEST,
serializedRequest = SafeParcelableSerializer.serializeToBytes(signInRequest),
googleSignInOptions = gso,
callingPackage = callingPackage
)
startActivityForResult(signInIntent, REQ_CODE_SIGN_IN)
}
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
Log.d(TAG, "onActivityResult: requestCode: $requestCode resultCode: $resultCode")
when (requestCode) {
REQ_CODE_FIDO -> handleFidoResult(resultCode, data)
REQ_CODE_SIGN_IN -> handleSignInResult(resultCode, data)
else -> finishWithGetException(GetCredentialUnknownException("Unexpected requestCode=$requestCode"))
}
}
private fun handleFidoResult(resultCode: Int, data: Intent?) {
Log.d(TAG, "handleFidoResult: data: $data")
if (resultCode != RESULT_OK || data == null) {
return if (isCreatePath) finishWithCreateException(CreateCredentialUnknownException("Passkey flow canceled"))
else finishWithGetException(GetCredentialCancellationException("Passkey flow canceled"))
}
runCatching {
val credentialBytes = data.getByteArrayExtra(FIDO2_KEY_CREDENTIAL_EXTRA)
?: throw IllegalStateException("FIDO returned no credential")
val publicKeyCredential = com.google.android.gms.fido.fido2.api.common.PublicKeyCredential
.deserializeFromBytes(credentialBytes)
(publicKeyCredential.response as? AuthenticatorErrorResponse)?.let { err ->
throw IllegalStateException(err.errorMessage ?: err.errorCode.toString())
}
val json = publicKeyCredential.toJson()
val credData = Bundle().apply {
putString(if (isCreatePath) PUBKEY_RES_REG_JSON_KEY else PUBKEY_RES_AUTH_JSON_KEY, json)
}
Log.d(TAG, "handleFidoResult: $credData")
finishWithCredential(PublicKeyCredential.TYPE_PUBLIC_KEY_CREDENTIAL, credData)
}.onFailure { e ->
Log.e(TAG, "handleFidoResult failed", e)
val msg = e.message ?: "FIDO result error"
if (isCreatePath) finishWithCreateException(CreateCredentialUnknownException(msg))
else finishWithGetException(GetCredentialUnknownException(msg))
}
}
private fun handleSignInResult(resultCode: Int, data: Intent?) {
if (resultCode != RESULT_OK || data == null) {
return finishWithGetException(GetCredentialCancellationException("Sign-in canceled"))
}
runCatching {
val bytes = data.getByteArrayExtra(AuthConstants.SIGN_IN_CREDENTIAL)
?: throw IllegalStateException("Sign-in result missing credential")
val credential = SafeParcelableSerializer.deserializeFromBytes(bytes, SignInCredential.CREATOR)
val credData = Bundle().apply {
putString(GOOGLE_ID_BUNDLE_KEY_ID, credential.id)
credential.googleIdToken?.let { putString(GOOGLE_ID_BUNDLE_KEY_ID_TOKEN, it) }
credential.displayName?.let { putString(GOOGLE_ID_BUNDLE_KEY_DISPLAY_NAME, it) }
credential.givenName?.let { putString(GOOGLE_ID_BUNDLE_KEY_GIVEN_NAME, it) }
credential.familyName?.let { putString(GOOGLE_ID_BUNDLE_KEY_FAMILY_NAME, it) }
credential.profilePictureUri?.let { putString(GOOGLE_ID_BUNDLE_KEY_PROFILE_PICTURE_URI, it.toString()) }
}
finishWithCredential(TYPE_GOOGLE_ID_TOKEN_CREDENTIAL, credData)
}.onFailure { e ->
Log.e(TAG, "handleSignInResult failed", e)
finishWithGetException(GetCredentialUnknownException(e.message ?: "Sign-in result error"))
}
}
private fun finishWithCredential(type: String, credentialData: Bundle) {
val responseBundle = Bundle().apply {
if (isCreatePath) {
putString(PROVIDER_EXTRA_CREATE_RESPONSE_TYPE, type)
putBundle(PROVIDER_EXTRA_CREATE_REQUEST_DATA, credentialData)
} else {
putString(PROVIDER_EXTRA_CREDENTIAL_TYPE, type)
putBundle(PROVIDER_EXTRA_CREDENTIAL_DATA, credentialData)
}
}
val extraKey = if (isCreatePath) EXTRA_CREATE_RESPONSE_BUNDLE else EXTRA_GET_RESPONSE_BUNDLE
Log.d(TAG, "finishWithCredential: extraKey: $extraKey responseBundle: $responseBundle")
setResult(RESULT_OK, Intent().putExtra(extraKey, responseBundle))
finish()
}
private fun finishWithGetException(e: androidx.credentials.exceptions.GetCredentialException) {
finishWithExceptionBundle(EXTRA_GET_EXCEPTION_BUNDLE, e.type, e.message ?: e.javaClass.simpleName)
}
private fun finishWithCreateException(e: androidx.credentials.exceptions.CreateCredentialException) {
finishWithExceptionBundle(EXTRA_CREATE_EXCEPTION_BUNDLE, e.type, e.message ?: e.javaClass.simpleName)
}
private fun finishWithExceptionBundle(extraKey: String, type: String, message: String) {
val bundle = Bundle().apply {
putString(PROVIDER_EXTRA_EXCEPTION_TYPE, type)
putString(PROVIDER_EXTRA_EXCEPTION_MESSAGE, message)
}
setResult(RESULT_OK, Intent().putExtra(extraKey, bundle))
finish()
}
private fun <T : Parcelable> readNestedParcelable(name: String, clazz: Class<T>): T? =
intent.getBundleExtra(name)?.let { bundle ->
bundle.classLoader = clazz.classLoader
BundleCompat.getParcelable(bundle, name, clazz)
}
companion object {
private const val REQ_CODE_FIDO = 0x1001
private const val REQ_CODE_SIGN_IN = 0x1002
private const val EXTRA_GET_RESPONSE_BUNDLE = "android.service.credentials.extra.GET_CREDENTIAL_RESPONSE"
private const val EXTRA_GET_EXCEPTION_BUNDLE = "android.service.credentials.extra.GET_CREDENTIAL_EXCEPTION"
private const val EXTRA_CREATE_RESPONSE_BUNDLE = "android.service.credentials.extra.CREATE_CREDENTIAL_RESPONSE"
private const val EXTRA_CREATE_EXCEPTION_BUNDLE = "android.service.credentials.extra.CREATE_CREDENTIAL_EXCEPTION"
private const val PROVIDER_EXTRA_CREDENTIAL_TYPE = "androidx.credentials.provider.extra.EXTRA_CREDENTIAL_TYPE"
private const val PROVIDER_EXTRA_CREDENTIAL_DATA = "androidx.credentials.provider.extra.EXTRA_CREDENTIAL_DATA"
private const val PROVIDER_EXTRA_CREATE_RESPONSE_TYPE = "androidx.credentials.provider.extra.CREATE_CREDENTIAL_RESPONSE_TYPE"
private const val PROVIDER_EXTRA_CREATE_REQUEST_DATA = "androidx.credentials.provider.extra.CREATE_CREDENTIAL_REQUEST_DATA"
private const val PROVIDER_EXTRA_EXCEPTION_TYPE = "androidx.credentials.provider.extra.CREATE_CREDENTIAL_EXCEPTION_TYPE"
private const val PROVIDER_EXTRA_EXCEPTION_MESSAGE = "androidx.credentials.provider.extra.CREATE_CREDENTIAL_EXCEPTION_MESSAGE"
private const val PUBKEY_REQ_JSON_KEY = "androidx.credentials.BUNDLE_KEY_REQUEST_JSON"
private const val PUBKEY_RES_AUTH_JSON_KEY = "androidx.credentials.BUNDLE_KEY_AUTHENTICATION_RESPONSE_JSON"
private const val PUBKEY_RES_REG_JSON_KEY = "androidx.credentials.BUNDLE_KEY_REGISTRATION_RESPONSE_JSON"
}
}

View file

@ -172,6 +172,7 @@ const val GOOGLE_ID_BUNDLE_KEY_GIVEN_NAME = "com.google.android.libraries.identi
const val GOOGLE_ID_BUNDLE_KEY_FAMILY_NAME = "com.google.android.libraries.identity.googleid.BUNDLE_KEY_FAMILY_NAME"
const val GOOGLE_ID_BUNDLE_KEY_PHONE_NUMBER = "com.google.android.libraries.identity.googleid.BUNDLE_KEY_PHONE_NUMBER"
const val GOOGLE_ID_BUNDLE_KEY_PROFILE_PICTURE_URI = "com.google.android.libraries.identity.googleid.BUNDLE_KEY_PROFILE_PICTURE_URI"
const val GOOGLE_ID_FILTER_BY_AUTHORIZED_ACCOUNTS = "com.google.android.libraries.identity.googleid.BUNDLE_KEY_FILTER_BY_AUTHORIZED_ACCOUNTS"
// Credential types
const val TYPE_GOOGLE_ID_TOKEN_CREDENTIAL = "com.google.android.libraries.identity.googleid.TYPE_GOOGLE_ID_TOKEN_CREDENTIAL"

View file

@ -18,14 +18,8 @@ import androidx.credentials.provider.ProviderGetCredentialRequest
import com.google.android.gms.fido.Fido.FIDO2_KEY_CREDENTIAL_EXTRA
import com.google.android.gms.fido.fido2.api.common.*
import org.json.JSONObject
import org.microg.gms.common.GmsService
import org.microg.gms.fido.core.ui.ACTION_FIDO_AUTHENTICATE
import org.microg.gms.fido.core.ui.AuthenticatorActivity.Companion.KEY_CALLER
import org.microg.gms.auth.credentials.buildFidoAuthenticateIntent
import org.microg.gms.fido.core.ui.AuthenticatorActivity.Companion.KEY_CREDENTIAL_ID
import org.microg.gms.fido.core.ui.AuthenticatorActivity.Companion.KEY_OPTIONS
import org.microg.gms.fido.core.ui.AuthenticatorActivity.Companion.KEY_SERVICE
import org.microg.gms.fido.core.ui.AuthenticatorActivity.Companion.KEY_SOURCE
import org.microg.gms.fido.core.ui.AuthenticatorActivity.Companion.KEY_TYPE
import org.microg.gms.fido.core.ui.AuthenticatorActivity.Companion.SOURCE_APP
import org.microg.gms.fido.core.ui.AuthenticatorActivity.Companion.SOURCE_BROWSER
import org.microg.gms.fido.core.ui.AuthenticatorActivity.Companion.TYPE_REGISTER
@ -50,7 +44,7 @@ class PublicKeyProxyActivity : CredentialProviderActivity() {
val credentialIdString = intent.getStringExtra(KEY_CREDENTIAL_ID)
val (optionsBytes, source) = buildRequestOptions(options, isBrowserRequest, request.callingAppInfo.origin, option.clientDataHash)
val fidoIntent = createFidoIntent(source, optionsBytes, request.callingAppInfo.packageName, TYPE_SIGN, credentialIdString)
val fidoIntent = buildFidoAuthenticateIntent(source, optionsBytes, request.callingAppInfo.packageName, TYPE_SIGN, credentialIdString)
startActivityForResult(fidoIntent, REQUEST_CODE_FIDO)
}
@ -76,7 +70,7 @@ class PublicKeyProxyActivity : CredentialProviderActivity() {
Log.d(TAG, "handlePasskeyCreate: options: $options")
val (optionsBytes, source) = buildCreationOptions(options, isBrowserRequest, origin, publicKeyRequest.clientDataHash)
val fidoIntent = createFidoIntent(source, optionsBytes, callingPackage, TYPE_REGISTER)
val fidoIntent = buildFidoAuthenticateIntent(source, optionsBytes, callingPackage, TYPE_REGISTER)
startActivityForResult(fidoIntent, REQUEST_CODE_FIDO)
Log.d(TAG, "Launched FIDO authenticator by PasskeyCreate")
@ -118,19 +112,6 @@ class PublicKeyProxyActivity : CredentialProviderActivity() {
}
}
fun createFidoIntent(
source: String, optionsBytes: ByteArray, callingPackage: String, type: String, credentialIdString: String? = null
): Intent = Intent(ACTION_FIDO_AUTHENTICATE).apply {
`package` = packageName
putExtra(KEY_SERVICE, GmsService.FIDO2_API.SERVICE_ID)
putExtra(KEY_SOURCE, source)
putExtra(KEY_TYPE, type)
putExtra(KEY_OPTIONS, optionsBytes)
putExtra(KEY_CALLER, callingPackage)
credentialIdString?.let { putExtra(KEY_CREDENTIAL_ID, it) }
}
private fun handleFidoSuccess(publicKeyCredential: PublicKeyCredential) = runCatching {
when (val response = publicKeyCredential.response) {
is AuthenticatorAttestationResponse -> {

View file

@ -20,10 +20,8 @@ import com.google.android.gms.auth.api.identity.SignInCredential
import com.google.android.gms.auth.api.signin.GoogleSignInOptions
import com.google.android.gms.common.internal.safeparcel.SafeParcelableSerializer
import org.microg.gms.auth.AuthConstants
import org.microg.gms.auth.signin.ACTION_ASSISTED_SIGN_IN
import org.microg.gms.auth.signin.CLIENT_PACKAGE_NAME
import org.microg.gms.auth.credentials.buildAssistedSignInIntent
import org.microg.gms.auth.signin.GET_SIGN_IN_INTENT_REQUEST
import org.microg.gms.auth.signin.GOOGLE_SIGN_IN_OPTIONS
private const val TAG = "SignInProxyActivity"
private const val REQUEST_CODE_SIGN_IN = 100
@ -32,31 +30,23 @@ private const val REQUEST_CODE_SIGN_IN = 100
class SignInProxyActivity : CredentialProviderActivity() {
override fun onProviderGetCredentialRequest(request: ProviderGetCredentialRequest) {
val bundle = Bundle().apply {
val signInRequest = GetSignInIntentRequest.builder()
.setServerClientId(intent.getStringExtra(GOOGLE_ID_SIWG_SERVER_CLIENT_ID) ?: "")
.apply {
intent.getStringExtra(GOOGLE_ID_SIWG_NONCE)?.let { setNonce(it) }
}
.build()
val googleSignInOptions = GoogleSignInOptions.Builder(GoogleSignInOptions.DEFAULT_SIGN_IN)
.requestEmail()
.requestIdToken(intent.getStringExtra(GOOGLE_ID_SIWG_SERVER_CLIENT_ID) ?: "")
.apply { intent.getStringExtra(GOOGLE_ID_SIWG_ACCOUNT_NAME)?.let { setAccountName(it) } }
.build()
putByteArray(GET_SIGN_IN_INTENT_REQUEST, SafeParcelableSerializer.serializeToBytes(signInRequest))
putByteArray(GOOGLE_SIGN_IN_OPTIONS, SafeParcelableSerializer.serializeToBytes(googleSignInOptions))
putString(CLIENT_PACKAGE_NAME, intent.getStringExtra(GOOGLE_ID_SIWG_CALLER_PACKAGE))
}
startActivityForResult(
Intent(ACTION_ASSISTED_SIGN_IN).apply {
`package` = packageName
putExtras(bundle)
},
REQUEST_CODE_SIGN_IN
val serverClientId = intent.getStringExtra(GOOGLE_ID_SIWG_SERVER_CLIENT_ID).orEmpty()
val signInRequest = GetSignInIntentRequest.builder()
.setServerClientId(serverClientId)
.apply { intent.getStringExtra(GOOGLE_ID_SIWG_NONCE)?.let { setNonce(it) } }
.build()
val googleSignInOptions = GoogleSignInOptions.Builder(GoogleSignInOptions.DEFAULT_SIGN_IN)
.requestEmail()
.requestIdToken(serverClientId)
.apply { intent.getStringExtra(GOOGLE_ID_SIWG_ACCOUNT_NAME)?.let { setAccountName(it) } }
.build()
val signInIntent = buildAssistedSignInIntent(
requestExtraKey = GET_SIGN_IN_INTENT_REQUEST,
serializedRequest = SafeParcelableSerializer.serializeToBytes(signInRequest),
googleSignInOptions = googleSignInOptions,
callingPackage = intent.getStringExtra(GOOGLE_ID_SIWG_CALLER_PACKAGE)
)
startActivityForResult(signInIntent, REQUEST_CODE_SIGN_IN)
}
override fun onProviderCreateCredentialRequest(request: ProviderCreateCredentialRequest) {

View file

@ -26,6 +26,8 @@ import org.microg.gms.fido.core.transport.TransportHandler
import org.microg.gms.fido.core.transport.TransportHandlerCallback
import org.microg.gms.utils.toBase64
import java.security.Signature
import java.security.cert.Certificate
import java.security.cert.X509Certificate
import java.security.interfaces.ECPublicKey
import kotlin.coroutines.resume
import kotlin.coroutines.resumeWithException
@ -122,7 +124,6 @@ class ScreenLockTransportHandler(private val activity: FragmentActivity, callbac
}
}
val (clientData, clientDataHash) = getClientDataAndHash(activity, options, callerPackage)
val aaguid = if (options.registerOptions.skipAttestation) ByteArray(16) else AAGUID
val keyId = store.createKey(options.rpId, clientDataHash)
val publicKey =
store.getPublicKey(options.rpId, keyId) ?: throw RequestHandlingException(ErrorCode.INVALID_STATE_ERR)
@ -130,6 +131,12 @@ class ScreenLockTransportHandler(private val activity: FragmentActivity, callbac
// We're ignoring the signature object as we don't need it for registration
val signature = getActiveSignature(options, callerPackage, keyId)
val skipAttestation = options.registerOptions.skipAttestation
val useAndroidKey = !skipAttestation && SDK_INT >= 24 &&
runCatching { store.getCertificateChain(options.rpId, keyId).hasValidLeafCertificate() }.getOrDefault(false)
val useSafetyNet = !skipAttestation && SDK_INT < 24
val aaguid = if (useAndroidKey || useSafetyNet) AAGUID else ByteArray(16)
val (x, y) = (publicKey as ECPublicKey).w.let { it.affineX to it.affineY }
val coseKey = CoseKey(EC2Algorithm.ES256, x, y, 1, 32)
val credentialId = CredentialId(1, keyId, options.rpId, publicKey)
@ -137,19 +144,20 @@ class ScreenLockTransportHandler(private val activity: FragmentActivity, callbac
val credentialData = getCredentialData(aaguid, credentialId, coseKey)
val authenticatorData = getAuthenticatorData(options.rpId, credentialData)
val attestationObject = if (options.registerOptions.skipAttestation) {
NoneAttestationObject(authenticatorData)
} else {
try {
if (SDK_INT >= 24) {
createAndroidKeyAttestation(signature, authenticatorData, clientDataHash, options.rpId, keyId)
} else {
createSafetyNetAttestation(authenticatorData, clientDataHash)
}
val attestationObject = when {
useAndroidKey -> try {
createAndroidKeyAttestation(signature, authenticatorData, clientDataHash, options.rpId, keyId)
} catch (e: Exception) {
Log.w("FidoScreenLockTransport", e)
NoneAttestationObject(authenticatorData)
}
useSafetyNet -> try {
createSafetyNetAttestation(authenticatorData, clientDataHash)
} catch (e: Exception) {
Log.w("FidoScreenLockTransport", e)
NoneAttestationObject(authenticatorData)
}
else -> NoneAttestationObject(authenticatorData)
}
return AuthenticatorResponseWithUser(
@ -180,6 +188,11 @@ class ScreenLockTransportHandler(private val activity: FragmentActivity, callbac
store.getCertificateChain(rpId, keyId).map { it.encoded })
}
private fun Array<Certificate>.hasValidLeafCertificate(): Boolean {
val leaf = firstOrNull() as? X509Certificate ?: return false
return runCatching { leaf.checkValidity() }.isSuccess
}
private suspend fun createSafetyNetAttestation(
authenticatorData: AuthenticatorData,
clientDataHash: ByteArray

View file

@ -0,0 +1,37 @@
/*
* SPDX-FileCopyrightText: 2026 microG Project Team
* SPDX-License-Identifier: Apache-2.0
*/
apply plugin: 'com.android.library'
android {
namespace "com.google.android.gms.identitycredentials"
compileSdkVersion androidCompileSdk
buildToolsVersion "$androidBuildVersionTools"
buildFeatures {
aidl = true
}
defaultConfig {
versionName version
minSdkVersion androidMinSdk
targetSdkVersion androidTargetSdk
}
compileOptions {
sourceCompatibility = 1.8
targetCompatibility = 1.8
}
}
description = 'microG implementation of play-services-identity-credentials'
dependencies {
api project(':play-services-base')
api project(':play-services-basement')
annotationProcessor project(':safe-parcel-processor')
}

View file

@ -0,0 +1,52 @@
/*
* SPDX-FileCopyrightText: 2026 microG Project Team
* SPDX-License-Identifier: Apache-2.0
*/
apply plugin: 'com.android.library'
apply plugin: 'kotlin-android'
dependencies {
api project(':play-services-identity-credentials')
implementation project(':play-services-base-core')
implementation project(':play-services-fido-core')
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlinVersion"
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core:$coroutineVersion"
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:$coroutineVersion"
}
android {
namespace "org.microg.gms.identitycredentials.core"
compileSdkVersion androidCompileSdk
buildToolsVersion "$androidBuildVersionTools"
defaultConfig {
versionName version
minSdkVersion androidMinSdk
targetSdkVersion androidTargetSdk
}
sourceSets {
main {
java.srcDirs = ['src/main/kotlin']
}
}
lintOptions {
disable 'MissingTranslation'
}
compileOptions {
sourceCompatibility = 1.8
targetCompatibility = 1.8
}
kotlinOptions {
jvmTarget = 1.8
}
}
description = 'microG service implementation for play-services-identity-credentials'

View file

@ -0,0 +1,15 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
~ SPDX-FileCopyrightText: 2026 microG Project Team
~ SPDX-License-Identifier: Apache-2.0
-->
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
<application>
<service android:name="org.microg.gms.identitycredentials.IdentityCredentialApiService">
<intent-filter>
<action android:name="com.google.android.gms.identitycredentials.service.START" />
</intent-filter>
</service>
</application>
</manifest>

View file

@ -0,0 +1,215 @@
/*
* SPDX-FileCopyrightText: 2026 microG Project Team
* SPDX-License-Identifier: Apache-2.0
*/
package org.microg.gms.identitycredentials
import android.app.PendingIntent
import android.content.ComponentName
import android.content.Context
import android.content.Intent
import android.os.Bundle
import android.util.Log
import androidx.core.app.PendingIntentCompat
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.LifecycleOwner
import androidx.lifecycle.lifecycleScope
import com.google.android.gms.common.ConnectionResult
import com.google.android.gms.common.Feature
import com.google.android.gms.common.api.ApiMetadata
import com.google.android.gms.common.api.CommonStatusCodes
import com.google.android.gms.common.api.Status
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 com.google.android.gms.identitycredentials.ClearCreationOptionsRequest
import com.google.android.gms.identitycredentials.ClearCredentialStateRequest
import com.google.android.gms.identitycredentials.ClearCredentialStateResponse
import com.google.android.gms.identitycredentials.ClearExportRequest
import com.google.android.gms.identitycredentials.ClearRegistryRequest
import com.google.android.gms.identitycredentials.CreateCredentialHandle
import com.google.android.gms.identitycredentials.CreateCredentialRequest
import com.google.android.gms.identitycredentials.CredentialInformation
import com.google.android.gms.identitycredentials.CredentialInformationRequest
import com.google.android.gms.identitycredentials.CredentialInformationResponse
import com.google.android.gms.identitycredentials.CredentialTransferCapabilities
import com.google.android.gms.identitycredentials.ExportCredentialsToDeviceSetupRequest
import com.google.android.gms.identitycredentials.GetCredentialRequest
import com.google.android.gms.identitycredentials.GetCredentialTransferCapabilitiesRequest
import com.google.android.gms.identitycredentials.ImportCredentialsForDeviceSetupRequest
import com.google.android.gms.identitycredentials.ImportCredentialsRequest
import com.google.android.gms.identitycredentials.PendingGetCredentialHandle
import com.google.android.gms.identitycredentials.RegisterCreationOptionsRequest
import com.google.android.gms.identitycredentials.RegisterExportRequest
import com.google.android.gms.identitycredentials.RegistrationRequest
import com.google.android.gms.identitycredentials.SignalCredentialStateRequest
import com.google.android.gms.identitycredentials.internal.IIdentityCredentialCallbacks
import com.google.android.gms.identitycredentials.internal.IIdentityCredentialService
import kotlinx.coroutines.launch
import org.microg.gms.BaseService
import org.microg.gms.common.AccountUtils
import org.microg.gms.common.GmsService
import org.microg.gms.fido.core.Database
import org.microg.gms.profile.Build
import org.microg.gms.profile.ProfileManager
private const val TAG = "IdentityCredentialApi"
private const val CHOOSER_ACTIVITY_CLASS = "org.microg.gms.auth.credentials.identity.IdentityCredentialChooserActivity"
const val EXTRA_GET_REQUEST = "org.microg.gms.identitycredentials.EXTRA_GET_REQUEST"
const val EXTRA_CREATE_REQUEST = "org.microg.gms.identitycredentials.EXTRA_CREATE_REQUEST"
const val EXTRA_CALLING_PACKAGE = "org.microg.gms.identitycredentials.EXTRA_CALLING_PACKAGE"
private val FEATURES = arrayOf(
Feature("GET_CREDENTIAL", 1),
Feature("CREDENTIAL_REGISTRY", 1),
Feature("CLEAR_REGISTRY", 2),
Feature("CLEAR_CREATION_OPTIONS", 1),
Feature("GET_CREDENTIAL_INFORMATION", 1),
Feature("CLEAR_CREDENTIAL_STATE", 1),
Feature("CREATE_CREDENTIAL", 3),
Feature("REGISTER_CREATION_OPTIONS", 1),
Feature("REGISTER_EXPORT", 1),
Feature("IMPORT_CREDENTIALS", 1),
Feature("SIGNAL_CREDENTIAL_STATE", 1),
Feature("CLEAR_EXPORT", 1),
Feature("IMPORT_CREDENTIALS_FOR_DEVICE_SETUP", 3),
Feature("EXPORT_CREDENTIALS_TO_DEVICE_SETUP", 3),
Feature("GET_CREDENTIAL_TRANSFER_CAPABILITIES", 3),
)
class IdentityCredentialApiService : BaseService(TAG, GmsService.IDENTITY_CREDENTIALS) {
override fun handleServiceRequest(callback: IGmsCallbacks, request: GetServiceRequest, service: GmsService) {
Log.d(TAG, "handleServiceRequest pkg=${request.packageName}")
val connectionInfo = ConnectionInfo()
connectionInfo.features = FEATURES
ProfileManager.ensureInitialized(this)
callback.onPostInitCompleteWithConnectionInfo(
ConnectionResult.SUCCESS,
IdentityCredentialApiServiceImpl(this, request.packageName, lifecycle).asBinder(),
connectionInfo
)
}
}
class IdentityCredentialApiServiceImpl(
private val context: Context,
private val clientPackageName: String,
override val lifecycle: Lifecycle,
) : IIdentityCredentialService.Stub(), LifecycleOwner {
override fun getCredential(callback: IIdentityCredentialCallbacks, request: GetCredentialRequest, apiMetadata: ApiMetadata) {
Log.d(TAG, "getCredential pkg=$clientPackageName options=${request.credentialOptions.size} origin=${request.origin}")
callback.onGetCredential(Status.SUCCESS, PendingGetCredentialHandle(buildChooserPendingIntent(request)), ApiMetadata.SKIP)
}
override fun createCredential(callback: IIdentityCredentialCallbacks, request: CreateCredentialRequest, apiMetadata: ApiMetadata) {
Log.d(TAG, "createCredential pkg=$clientPackageName type=${request.type} origin=${request.origin}")
callback.onCreateCredential(Status.SUCCESS, CreateCredentialHandle(buildCreateChooserPendingIntent(request), null), ApiMetadata.SKIP)
}
override fun clearCredentialState(callback: IIdentityCredentialCallbacks, request: ClearCredentialStateRequest, apiMetadata: ApiMetadata) {
Log.d(TAG, "clearCredentialState pkg=$clientPackageName")
callback.onClearCredentialState(Status.SUCCESS, ClearCredentialStateResponse(), ApiMetadata.SKIP)
}
override fun getCredentialInformation(callback: IIdentityCredentialCallbacks, request: CredentialInformationRequest, apiMetadata: ApiMetadata) {
val packageNames = request.packageNames.orEmpty()
Log.d(TAG, "getCredentialInformation pkg=$clientPackageName count=${packageNames.size}")
if (Build.VERSION.SDK_INT < 34) {
callback.onGetCredentialInformation(Status.SUCCESS, CredentialInformationResponse(emptyList()))
return
}
lifecycleScope.launch {
fun resolveCredentialInformation(packageName: String): CredentialInformation {
val installed = runCatching { context.packageManager.getPackageInfo(packageName, 0) }.isSuccess
if (!installed) return CredentialInformation(packageName, 0, 0, 0, 0)
val hasPasskey = runCatching { Database(context).getKnownRegistrationInfo(packageName).isNotEmpty() }.getOrDefault(false)
val hasGoogleAccount = AccountUtils.get(context).getSelectedAccount(packageName) != null
return CredentialInformation(packageName, 0, if (hasPasskey) 1 else 0, if (hasGoogleAccount) 1 else 0, 0)
}
val infos = packageNames.filterNotNull().map { resolveCredentialInformation(it) }
runCatching { callback.onGetCredentialInformation(Status.SUCCESS, CredentialInformationResponse(infos)) }
.onFailure { Log.w(TAG, "getCredentialInformation callback failed", it) }
}
}
override fun register(callback: IIdentityCredentialCallbacks, request: RegistrationRequest, apiMetadata: ApiMetadata) {
Log.d(TAG, "register: not implemented")
callback.onRegister(Status(CommonStatusCodes.API_NOT_CONNECTED), null, ApiMetadata.SKIP)
}
override fun clearRegistry(callback: IIdentityCredentialCallbacks, request: ClearRegistryRequest, apiMetadata: ApiMetadata) {
Log.d(TAG, "clearRegistry: not implemented")
callback.onClearRegistry(Status(CommonStatusCodes.API_NOT_CONNECTED), null, ApiMetadata.SKIP)
}
override fun importCredentials(callback: IIdentityCredentialCallbacks, request: ImportCredentialsRequest, apiMetadata: ApiMetadata) {
Log.d(TAG, "importCredentials: not implemented")
callback.onImportCredentials(Status(CommonStatusCodes.API_NOT_CONNECTED), null, ApiMetadata.SKIP)
}
override fun registerExport(callback: IIdentityCredentialCallbacks, request: RegisterExportRequest, apiMetadata: ApiMetadata) {
Log.d(TAG, "registerExport: not implemented")
callback.onRegisterExport(Status(CommonStatusCodes.API_NOT_CONNECTED), null, ApiMetadata.SKIP)
}
override fun registerCreationOptions(callback: IIdentityCredentialCallbacks, request: RegisterCreationOptionsRequest, apiMetadata: ApiMetadata) {
Log.d(TAG, "registerCreationOptions: not implemented")
callback.onRegisterCreationOptions(Status(CommonStatusCodes.API_NOT_CONNECTED), null, ApiMetadata.SKIP)
}
override fun signalCredentialState(callback: IIdentityCredentialCallbacks, request: SignalCredentialStateRequest, apiMetadata: ApiMetadata) {
Log.d(TAG, "signalCredentialState: not implemented")
callback.onSignalCredentialState(Status(CommonStatusCodes.API_NOT_CONNECTED), null, ApiMetadata.SKIP)
}
override fun clearExport(callback: IIdentityCredentialCallbacks, request: ClearExportRequest, apiMetadata: ApiMetadata) {
Log.d(TAG, "clearExport: not implemented")
callback.onClearExport(Status(CommonStatusCodes.API_NOT_CONNECTED), null, ApiMetadata.SKIP)
}
override fun importCredentialsForDeviceSetup(callback: IIdentityCredentialCallbacks, request: ImportCredentialsForDeviceSetupRequest, apiMetadata: ApiMetadata) {
Log.d(TAG, "importCredentialsForDeviceSetup: not implemented")
callback.onImportCredentialsForDeviceSetup(Status(CommonStatusCodes.API_NOT_CONNECTED), null, ApiMetadata.SKIP)
}
override fun exportCredentialsToDeviceSetup(callback: IIdentityCredentialCallbacks, request: ExportCredentialsToDeviceSetupRequest, apiMetadata: ApiMetadata) {
Log.d(TAG, "exportCredentialsToDeviceSetup: not implemented")
callback.onExportCredentialsToDeviceSetup(Status(CommonStatusCodes.API_NOT_CONNECTED), null, ApiMetadata.SKIP)
}
override fun getCredentialTransferCapabilities(callback: IIdentityCredentialCallbacks, request: GetCredentialTransferCapabilitiesRequest, apiMetadata: ApiMetadata) {
Log.d(TAG, "getCredentialTransferCapabilities pkg=$clientPackageName")
callback.onGetCredentialTransferCapabilities(Status.SUCCESS, CredentialTransferCapabilities(Bundle.EMPTY), ApiMetadata.SKIP)
}
override fun clearCreationOptions(callback: IIdentityCredentialCallbacks, request: ClearCreationOptionsRequest, apiMetadata: ApiMetadata) {
Log.d(TAG, "clearCreationOptions: not implemented")
callback.onClearCreationOptions(Status(CommonStatusCodes.API_NOT_CONNECTED), null, ApiMetadata.SKIP)
}
private fun buildChooserPendingIntent(request: GetCredentialRequest): PendingIntent =
buildChooserPendingIntent(request.hashCode()) {
putExtra(EXTRA_GET_REQUEST, Bundle().apply { putParcelable(EXTRA_GET_REQUEST, request) })
}
private fun buildCreateChooserPendingIntent(request: CreateCredentialRequest): PendingIntent =
buildChooserPendingIntent(request.hashCode()) {
putExtra(EXTRA_CREATE_REQUEST, Bundle().apply { putParcelable(EXTRA_CREATE_REQUEST, request) })
}
private inline fun buildChooserPendingIntent(requestCode: Int, configure: Intent.() -> Unit): PendingIntent {
val intent = Intent().apply {
component = ComponentName(context.packageName, CHOOSER_ACTIVITY_CLASS)
putExtra(EXTRA_CALLING_PACKAGE, clientPackageName)
configure()
}
val flags = PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_ONE_SHOT
return PendingIntentCompat.getActivity(context, requestCode, intent, flags, true)!!
}
}

View file

@ -0,0 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
</manifest>

View file

@ -0,0 +1,8 @@
/*
* SPDX-FileCopyrightText: 2026 microG Project Team
* SPDX-License-Identifier: Apache-2.0
*/
package com.google.android.gms.identitycredentials;
parcelable ClearCreationOptionsRequest;

View file

@ -0,0 +1,8 @@
/*
* SPDX-FileCopyrightText: 2026 microG Project Team
* SPDX-License-Identifier: Apache-2.0
*/
package com.google.android.gms.identitycredentials;
parcelable ClearCreationOptionsResponse;

View file

@ -0,0 +1,8 @@
/*
* SPDX-FileCopyrightText: 2026 microG Project Team
* SPDX-License-Identifier: Apache-2.0
*/
package com.google.android.gms.identitycredentials;
parcelable ClearCredentialStateRequest;

View file

@ -0,0 +1,8 @@
/*
* SPDX-FileCopyrightText: 2026 microG Project Team
* SPDX-License-Identifier: Apache-2.0
*/
package com.google.android.gms.identitycredentials;
parcelable ClearCredentialStateResponse;

View file

@ -0,0 +1,8 @@
/*
* SPDX-FileCopyrightText: 2026 microG Project Team
* SPDX-License-Identifier: Apache-2.0
*/
package com.google.android.gms.identitycredentials;
parcelable ClearExportRequest;

View file

@ -0,0 +1,8 @@
/*
* SPDX-FileCopyrightText: 2026 microG Project Team
* SPDX-License-Identifier: Apache-2.0
*/
package com.google.android.gms.identitycredentials;
parcelable ClearExportResponse;

View file

@ -0,0 +1,8 @@
/*
* SPDX-FileCopyrightText: 2026 microG Project Team
* SPDX-License-Identifier: Apache-2.0
*/
package com.google.android.gms.identitycredentials;
parcelable ClearRegistryRequest;

View file

@ -0,0 +1,8 @@
/*
* SPDX-FileCopyrightText: 2026 microG Project Team
* SPDX-License-Identifier: Apache-2.0
*/
package com.google.android.gms.identitycredentials;
parcelable ClearRegistryResponse;

View file

@ -0,0 +1,8 @@
/*
* SPDX-FileCopyrightText: 2026 microG Project Team
* SPDX-License-Identifier: Apache-2.0
*/
package com.google.android.gms.identitycredentials;
parcelable CreateCredentialHandle;

View file

@ -0,0 +1,8 @@
/*
* SPDX-FileCopyrightText: 2026 microG Project Team
* SPDX-License-Identifier: Apache-2.0
*/
package com.google.android.gms.identitycredentials;
parcelable CreateCredentialRequest;

View file

@ -0,0 +1,8 @@
/*
* SPDX-FileCopyrightText: 2026 microG Project Team
* SPDX-License-Identifier: Apache-2.0
*/
package com.google.android.gms.identitycredentials;
parcelable CreateCredentialResponse;

View file

@ -0,0 +1,8 @@
/*
* SPDX-FileCopyrightText: 2026 microG Project Team
* SPDX-License-Identifier: Apache-2.0
*/
package com.google.android.gms.identitycredentials;
parcelable CredentialInformationRequest;

View file

@ -0,0 +1,8 @@
/*
* SPDX-FileCopyrightText: 2026 microG Project Team
* SPDX-License-Identifier: Apache-2.0
*/
package com.google.android.gms.identitycredentials;
parcelable CredentialInformationResponse;

View file

@ -0,0 +1,8 @@
/*
* SPDX-FileCopyrightText: 2026 microG Project Team
* SPDX-License-Identifier: Apache-2.0
*/
package com.google.android.gms.identitycredentials;
parcelable CredentialOption;

View file

@ -0,0 +1,8 @@
/*
* SPDX-FileCopyrightText: 2026 microG Project Team
* SPDX-License-Identifier: Apache-2.0
*/
package com.google.android.gms.identitycredentials;
parcelable CredentialTransferCapabilities;

View file

@ -0,0 +1,8 @@
/*
* SPDX-FileCopyrightText: 2026 microG Project Team
* SPDX-License-Identifier: Apache-2.0
*/
package com.google.android.gms.identitycredentials;
parcelable ExportCredentialsToDeviceSetupRequest;

View file

@ -0,0 +1,8 @@
/*
* SPDX-FileCopyrightText: 2026 microG Project Team
* SPDX-License-Identifier: Apache-2.0
*/
package com.google.android.gms.identitycredentials;
parcelable ExportCredentialsToDeviceSetupResponse;

View file

@ -0,0 +1,8 @@
/*
* SPDX-FileCopyrightText: 2026 microG Project Team
* SPDX-License-Identifier: Apache-2.0
*/
package com.google.android.gms.identitycredentials;
parcelable GetCredentialRequest;

View file

@ -0,0 +1,8 @@
/*
* SPDX-FileCopyrightText: 2026 microG Project Team
* SPDX-License-Identifier: Apache-2.0
*/
package com.google.android.gms.identitycredentials;
parcelable GetCredentialTransferCapabilitiesRequest;

View file

@ -0,0 +1,8 @@
/*
* SPDX-FileCopyrightText: 2026 microG Project Team
* SPDX-License-Identifier: Apache-2.0
*/
package com.google.android.gms.identitycredentials;
parcelable ImportCredentialsForDeviceSetupRequest;

View file

@ -0,0 +1,8 @@
/*
* SPDX-FileCopyrightText: 2026 microG Project Team
* SPDX-License-Identifier: Apache-2.0
*/
package com.google.android.gms.identitycredentials;
parcelable ImportCredentialsForDeviceSetupResponse;

View file

@ -0,0 +1,8 @@
/*
* SPDX-FileCopyrightText: 2026 microG Project Team
* SPDX-License-Identifier: Apache-2.0
*/
package com.google.android.gms.identitycredentials;
parcelable ImportCredentialsRequest;

View file

@ -0,0 +1,8 @@
/*
* SPDX-FileCopyrightText: 2026 microG Project Team
* SPDX-License-Identifier: Apache-2.0
*/
package com.google.android.gms.identitycredentials;
parcelable PendingGetCredentialHandle;

View file

@ -0,0 +1,8 @@
/*
* SPDX-FileCopyrightText: 2026 microG Project Team
* SPDX-License-Identifier: Apache-2.0
*/
package com.google.android.gms.identitycredentials;
parcelable PendingImportCredentialsHandle;

View file

@ -0,0 +1,8 @@
/*
* SPDX-FileCopyrightText: 2026 microG Project Team
* SPDX-License-Identifier: Apache-2.0
*/
package com.google.android.gms.identitycredentials;
parcelable RegisterCreationOptionsRequest;

View file

@ -0,0 +1,8 @@
/*
* SPDX-FileCopyrightText: 2026 microG Project Team
* SPDX-License-Identifier: Apache-2.0
*/
package com.google.android.gms.identitycredentials;
parcelable RegisterCreationOptionsResponse;

View file

@ -0,0 +1,8 @@
/*
* SPDX-FileCopyrightText: 2026 microG Project Team
* SPDX-License-Identifier: Apache-2.0
*/
package com.google.android.gms.identitycredentials;
parcelable RegisterExportRequest;

View file

@ -0,0 +1,8 @@
/*
* SPDX-FileCopyrightText: 2026 microG Project Team
* SPDX-License-Identifier: Apache-2.0
*/
package com.google.android.gms.identitycredentials;
parcelable RegisterExportResponse;

View file

@ -0,0 +1,8 @@
/*
* SPDX-FileCopyrightText: 2026 microG Project Team
* SPDX-License-Identifier: Apache-2.0
*/
package com.google.android.gms.identitycredentials;
parcelable RegistrationRequest;

View file

@ -0,0 +1,8 @@
/*
* SPDX-FileCopyrightText: 2026 microG Project Team
* SPDX-License-Identifier: Apache-2.0
*/
package com.google.android.gms.identitycredentials;
parcelable RegistrationResponse;

View file

@ -0,0 +1,8 @@
/*
* SPDX-FileCopyrightText: 2026 microG Project Team
* SPDX-License-Identifier: Apache-2.0
*/
package com.google.android.gms.identitycredentials;
parcelable SignalCredentialStateRequest;

View file

@ -0,0 +1,8 @@
/*
* SPDX-FileCopyrightText: 2026 microG Project Team
* SPDX-License-Identifier: Apache-2.0
*/
package com.google.android.gms.identitycredentials;
parcelable SignalCredentialStateResponse;

View file

@ -0,0 +1,44 @@
/*
* SPDX-FileCopyrightText: 2026 microG Project Team
* SPDX-License-Identifier: Apache-2.0
*/
package com.google.android.gms.identitycredentials.internal;
import com.google.android.gms.common.api.ApiMetadata;
import com.google.android.gms.common.api.Status;
import com.google.android.gms.identitycredentials.ClearCreationOptionsResponse;
import com.google.android.gms.identitycredentials.ClearCredentialStateResponse;
import com.google.android.gms.identitycredentials.ClearExportResponse;
import com.google.android.gms.identitycredentials.ClearRegistryResponse;
import com.google.android.gms.identitycredentials.CreateCredentialHandle;
import com.google.android.gms.identitycredentials.CreateCredentialResponse;
import com.google.android.gms.identitycredentials.CredentialInformationResponse;
import com.google.android.gms.identitycredentials.CredentialTransferCapabilities;
import com.google.android.gms.identitycredentials.ExportCredentialsToDeviceSetupResponse;
import com.google.android.gms.identitycredentials.ImportCredentialsForDeviceSetupResponse;
import com.google.android.gms.identitycredentials.PendingGetCredentialHandle;
import com.google.android.gms.identitycredentials.PendingImportCredentialsHandle;
import com.google.android.gms.identitycredentials.RegisterCreationOptionsResponse;
import com.google.android.gms.identitycredentials.RegisterExportResponse;
import com.google.android.gms.identitycredentials.RegistrationResponse;
import com.google.android.gms.identitycredentials.SignalCredentialStateResponse;
interface IIdentityCredentialCallbacks {
void onGetCredential(in Status status, in PendingGetCredentialHandle handle, in ApiMetadata apiMetadata) = 0;
void onRegister(in Status status, in RegistrationResponse response, in ApiMetadata apiMetadata) = 1;
void onClearRegistry(in Status status, in ClearRegistryResponse response, in ApiMetadata apiMetadata) = 2;
void onImportCredentials(in Status status, in PendingImportCredentialsHandle handle, in ApiMetadata apiMetadata) = 3;
void onRegisterExport(in Status status, in RegisterExportResponse response, in ApiMetadata apiMetadata) = 4;
void onCreateCredentialLegacy(in Status status, in CreateCredentialResponse response, in ApiMetadata apiMetadata) = 5;
void onCreateCredential(in Status status, in CreateCredentialHandle handle, in ApiMetadata apiMetadata) = 6;
void onRegisterCreationOptions(in Status status, in RegisterCreationOptionsResponse response, in ApiMetadata apiMetadata) = 7;
void onClearCredentialState(in Status status, in ClearCredentialStateResponse response, in ApiMetadata apiMetadata) = 8;
void onSignalCredentialState(in Status status, in SignalCredentialStateResponse response, in ApiMetadata apiMetadata) = 9;
void onClearExport(in Status status, in ClearExportResponse response, in ApiMetadata apiMetadata) = 10;
void onImportCredentialsForDeviceSetup(in Status status, in ImportCredentialsForDeviceSetupResponse response, in ApiMetadata apiMetadata) = 11;
void onExportCredentialsToDeviceSetup(in Status status, in ExportCredentialsToDeviceSetupResponse response, in ApiMetadata apiMetadata) = 12;
void onGetCredentialTransferCapabilities(in Status status, in CredentialTransferCapabilities capabilities, in ApiMetadata apiMetadata) = 13;
void onClearCreationOptions(in Status status, in ClearCreationOptionsResponse response, in ApiMetadata apiMetadata) = 14;
void onGetCredentialInformation(in Status status, in CredentialInformationResponse response) = 15;
}

View file

@ -0,0 +1,42 @@
/*
* SPDX-FileCopyrightText: 2026 microG Project Team
* SPDX-License-Identifier: Apache-2.0
*/
package com.google.android.gms.identitycredentials.internal;
import com.google.android.gms.common.api.ApiMetadata;
import com.google.android.gms.identitycredentials.ClearCreationOptionsRequest;
import com.google.android.gms.identitycredentials.ClearCredentialStateRequest;
import com.google.android.gms.identitycredentials.ClearExportRequest;
import com.google.android.gms.identitycredentials.ClearRegistryRequest;
import com.google.android.gms.identitycredentials.CreateCredentialRequest;
import com.google.android.gms.identitycredentials.CredentialInformationRequest;
import com.google.android.gms.identitycredentials.ExportCredentialsToDeviceSetupRequest;
import com.google.android.gms.identitycredentials.GetCredentialRequest;
import com.google.android.gms.identitycredentials.GetCredentialTransferCapabilitiesRequest;
import com.google.android.gms.identitycredentials.ImportCredentialsForDeviceSetupRequest;
import com.google.android.gms.identitycredentials.ImportCredentialsRequest;
import com.google.android.gms.identitycredentials.RegisterCreationOptionsRequest;
import com.google.android.gms.identitycredentials.RegisterExportRequest;
import com.google.android.gms.identitycredentials.RegistrationRequest;
import com.google.android.gms.identitycredentials.SignalCredentialStateRequest;
import com.google.android.gms.identitycredentials.internal.IIdentityCredentialCallbacks;
interface IIdentityCredentialService {
void getCredential(IIdentityCredentialCallbacks callbacks, in GetCredentialRequest request, in ApiMetadata apiMetadata) = 0;
void register(IIdentityCredentialCallbacks callbacks, in RegistrationRequest request, in ApiMetadata apiMetadata) = 1;
void clearRegistry(IIdentityCredentialCallbacks callbacks, in ClearRegistryRequest request, in ApiMetadata apiMetadata) = 2;
void importCredentials(IIdentityCredentialCallbacks callbacks, in ImportCredentialsRequest request, in ApiMetadata apiMetadata) = 3;
void registerExport(IIdentityCredentialCallbacks callbacks, in RegisterExportRequest request, in ApiMetadata apiMetadata) = 4;
void createCredential(IIdentityCredentialCallbacks callbacks, in CreateCredentialRequest request, in ApiMetadata apiMetadata) = 5;
void registerCreationOptions(IIdentityCredentialCallbacks callbacks, in RegisterCreationOptionsRequest request, in ApiMetadata apiMetadata) = 7;
void clearCredentialState(IIdentityCredentialCallbacks callbacks, in ClearCredentialStateRequest request, in ApiMetadata apiMetadata) = 8;
void signalCredentialState(IIdentityCredentialCallbacks callbacks, in SignalCredentialStateRequest request, in ApiMetadata apiMetadata) = 9;
void clearExport(IIdentityCredentialCallbacks callbacks, in ClearExportRequest request, in ApiMetadata apiMetadata) = 10;
void importCredentialsForDeviceSetup(IIdentityCredentialCallbacks callbacks, in ImportCredentialsForDeviceSetupRequest request, in ApiMetadata apiMetadata) = 11;
void exportCredentialsToDeviceSetup(IIdentityCredentialCallbacks callbacks, in ExportCredentialsToDeviceSetupRequest request, in ApiMetadata apiMetadata) = 12;
void getCredentialTransferCapabilities(IIdentityCredentialCallbacks callbacks, in GetCredentialTransferCapabilitiesRequest request, in ApiMetadata apiMetadata) = 13;
void clearCreationOptions(IIdentityCredentialCallbacks callbacks, in ClearCreationOptionsRequest request, in ApiMetadata apiMetadata) = 14;
void getCredentialInformation(IIdentityCredentialCallbacks callbacks, in CredentialInformationRequest request, in ApiMetadata apiMetadata) = 15;
}

View file

@ -0,0 +1,103 @@
/*
* SPDX-FileCopyrightText: 2026 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.identitycredentials;
import android.os.Parcel;
import android.os.Parcelable;
import androidx.annotation.NonNull;
import java.util.ArrayList;
import java.util.List;
/**
* Information pertaining to the calling application.
* <p>
* The {@code packageCertificates} will either return a single byte-array corresponding to the oldest available signature for pre-P devices; for P+
* devices, it will return the full rotation history (including the signature used to sign the package) or an empty list. The empty list means the
* package was not found or the package does not have any trust-worthy signatures.
*/
public class CallingAppInfoParcelable implements Parcelable {
@NonNull
private final String packageName;
@NonNull
private final List<byte[]> packageCertificates;
@NonNull
private final String origin;
public CallingAppInfoParcelable(@NonNull String packageName, @NonNull List<byte[]> packageCertificates, @NonNull String origin) {
this.packageName = packageName;
this.packageCertificates = packageCertificates;
this.origin = origin;
}
@Override
public int describeContents() {
return 0;
}
/**
* the calling origin
*/
@NonNull
public String getOrigin() {
return origin;
}
/**
* a list of byte arrays, one for each rotated signature in raw bytes
*/
@NonNull
public List<byte[]> getPackageCertificates() {
return packageCertificates;
}
/**
* the calling app package name
*/
@NonNull
public String getPackageName() {
return packageName;
}
@Override
public void writeToParcel(@NonNull Parcel dest, int flags) {
dest.writeString(packageName);
dest.writeInt(packageCertificates.size());
for (byte[] packageCertificate : packageCertificates) {
dest.writeInt(packageCertificate.length);
dest.writeByteArray(packageCertificate);
}
dest.writeString(origin);
}
public static final Creator<CallingAppInfoParcelable> CREATOR = new Creator<CallingAppInfoParcelable>() {
@Override
public CallingAppInfoParcelable createFromParcel(Parcel source) {
String packageName = source.readString();
int numPackageCertificates = source.readInt();
if (packageName == null || numPackageCertificates < 0) {
return null;
}
List<byte[]> packageCertificates = new ArrayList<>(numPackageCertificates);
for (int i = 0; i < numPackageCertificates; i++) {
byte[] packageCertificate = new byte[source.readInt()];
source.readByteArray(packageCertificate);
packageCertificates.add(packageCertificate);
}
String origin = source.readString();
return new CallingAppInfoParcelable(packageName, packageCertificates, origin);
}
@Override
public CallingAppInfoParcelable[] newArray(int size) {
return new CallingAppInfoParcelable[size];
}
};
}

View file

@ -0,0 +1,138 @@
/*
* SPDX-FileCopyrightText: 2026 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.identitycredentials;
import android.os.Parcel;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
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 java.util.List;
/**
* A request to clear the registries stored for your app.
*/
@SafeParcelable.Class
public class ClearCreationOptionsRequest extends AbstractSafeParcelable {
@Field(value = 1, getterName = "getDeleteAll", defaultValue = "true")
private final boolean deleteAll;
@Field(value = 2, getterName = "getClearTypedRegistryOption")
@Nullable
private final ClearTypedCreationOption clearTypedRegistryOption;
/**
* Cosntructs a request to clear all registries for your app that was registered with the IdentityCredentials.registerCredentials API.
*/
public ClearCreationOptionsRequest() {
this(true, null);
}
/**
* constructs an instance of {@link ClearCreationOptionsRequest}
*
* @param deleteAll whether to delete all registries for your app
* @param clearTypedRegistryOption an option to clear the registries for a given type that matches the {@code RegisterCreationOptionsRequest.type} provided during registration
*/
@Constructor
public ClearCreationOptionsRequest(@Param(1) boolean deleteAll, @Param(2) @Nullable ClearTypedCreationOption clearTypedRegistryOption) {
this.deleteAll = deleteAll;
this.clearTypedRegistryOption = clearTypedRegistryOption;
}
/**
* whether to delete all registries for your app
*/
public boolean getDeleteAll() {
return deleteAll;
}
/**
* an option to clear the registries for a given type that matches the RegisterCreationOptionsRequest.type provided during registration
*/
@Nullable
public ClearTypedCreationOption getClearTypedRegistryOption() {
return clearTypedRegistryOption;
}
@Override
public void writeToParcel(@NonNull Parcel dest, int flags) {
CREATOR.writeToParcel(this, dest, flags);
}
public static final SafeParcelableCreatorAndWriter<ClearCreationOptionsRequest> CREATOR = findCreator(ClearCreationOptionsRequest.class);
/**
* A request to configure how to clear the registries for a given type.
* <p>
* The order of the conditions are important. If {@code deleteAllForType} is true, then the other conditions are ignored and all the
* registries for the given type are deleted. Otherwise, the registries with the IDs provided in {@code registryIds} will be deleted.
*/
@Class
public static class ClearTypedCreationOption extends AbstractSafeParcelable {
@Field(value = 1, getterName = "getDeleteAllForType")
private final boolean deleteAllForType;
@Field(value = 2, getterName = "getType")
@NonNull
private final String type;
@Field(value = 3, getterName = "getRegistryIds")
@NonNull
private final List<String> registryIds;
/**
* constructs an instance of {@link ClearTypedCreationOption}
*
* @param deleteAllForType whether to delete all registries for the given type
* @param type the type of registry to clear, matching the RegistrationRequest.type provided during registration
* @param registryIds the IDs of the registries for the given type to delete
*/
@Constructor
public ClearTypedCreationOption(@Param(1) boolean deleteAllForType, @NonNull @Param(2) String type, @NonNull @Param(3) List<String> registryIds) {
this.deleteAllForType = deleteAllForType;
this.type = type;
this.registryIds = registryIds;
}
/**
* whether to delete all registries for the given type
*/
public final boolean getDeleteAllForType() {
return this.deleteAllForType;
}
/**
* the IDs of the registries for the given type to delete
*/
@NonNull
public final List<String> getRegistryIds() {
return this.registryIds;
}
/**
* the type of registry to clear, matching the RegistrationRequest.type provided during registration
*/
@NonNull
public final String getType() {
return this.type;
}
@Override
public void writeToParcel(@NonNull Parcel dest, int flags) {
CREATOR.writeToParcel(this, dest, flags);
}
public static final SafeParcelableCreatorAndWriter<ClearTypedCreationOption> CREATOR = findCreator(ClearTypedCreationOption.class);
}
}

View file

@ -0,0 +1,49 @@
/*
* SPDX-FileCopyrightText: 2026 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.identitycredentials;
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;
/**
* Response of a registry deletion operation.
*/
@SafeParcelable.Class
public class ClearCreationOptionsResponse extends AbstractSafeParcelable {
@Field(value = 1, getterName = "isDeleted")
private final boolean isDeleted;
/**
* constructs an instance of {@link ClearCreationOptionsResponse}
* @param isDeleted if true, indicates clear operation deleted some registries, otherwise indicates there was no data to delete; unexpected failures will be thrown as exceptions
*/
@Constructor
public ClearCreationOptionsResponse(@Param(1) boolean isDeleted) {
this.isDeleted = isDeleted;
}
/**
* if true, indicates clear operation deleted some registries, otherwise indicates there was no data to delete; unexpected failures will be thrown as exceptions
*/
public final boolean isDeleted() {
return this.isDeleted;
}
@Override
public void writeToParcel(@NonNull Parcel dest, int flags) {
CREATOR.writeToParcel(this, dest, flags);
}
public static final SafeParcelableCreatorAndWriter<ClearCreationOptionsResponse> CREATOR = findCreator(ClearCreationOptionsResponse.class);
}

View file

@ -0,0 +1,31 @@
/*
* SPDX-FileCopyrightText: 2026 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.identitycredentials;
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;
/**
* Data interface for clearing a user's credential state from the credential providers.
*/
@SafeParcelable.Class
public class ClearCredentialStateRequest extends AbstractSafeParcelable {
@Override
public void writeToParcel(@NonNull Parcel dest, int flags) {
CREATOR.writeToParcel(this, dest, flags);
}
public static final SafeParcelableCreatorAndWriter<ClearCredentialStateRequest> CREATOR = findCreator(ClearCredentialStateRequest.class);
}

View file

@ -0,0 +1,31 @@
/*
* SPDX-FileCopyrightText: 2026 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.identitycredentials;
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;
/**
* Response of a clear credential state request.
*/
@SafeParcelable.Class
public class ClearCredentialStateResponse extends AbstractSafeParcelable {
@Override
public void writeToParcel(@NonNull Parcel dest, int flags) {
CREATOR.writeToParcel(this, dest, flags);
}
public static final SafeParcelableCreatorAndWriter<ClearCredentialStateResponse> CREATOR = findCreator(ClearCredentialStateResponse.class);
}

View file

@ -0,0 +1,74 @@
/*
* SPDX-FileCopyrightText: 2026 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.identitycredentials;
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 java.util.List;
/**
* A request to clear the registries stored for your app.
* <p>
* The order of the conditions are important. If {@code deleteAll} is true, then the other conditions are ignored, and all the registries for your app that
* was registered with the {@link IdentityCredentialClient#registerExport} API are deleted.
*/
@SafeParcelable.Class
public class ClearExportRequest extends AbstractSafeParcelable {
@Field(value = 1, getterName = "getDeleteAll")
private final boolean deleteAll;
@Field(value = 2, getterName = "getRegistryIds")
@NonNull
private final List<String> registryIds;
/**
* constructs an instance of {@link ClearExportRequest}
*
* @param deleteAll whether to delete all export registries for your app
* @param registryIds the IDs of the registries for the given type to delete
*/
@Constructor
public ClearExportRequest(@Param(1) boolean deleteAll, @NonNull @Param(2) List<String> registryIds) {
this.deleteAll = deleteAll;
this.registryIds = registryIds;
}
/**
* whether to delete all export registries for your app
*/
public final boolean getDeleteAll() {
return this.deleteAll;
}
/**
* the IDs of the registries for the given type to delete
*/
@NonNull
public final List<String> getRegistryIds() {
return this.registryIds;
}
@NonNull
public final ClearRegistryRequest.ClearTypedRegistryOption getClearRegistryOption() {
return new ClearRegistryRequest.ClearTypedRegistryOption(this.deleteAll, "androidx.identitycredentials.TYPE_CREDENTIALS_SYNC", false, this.registryIds);
}
@Override
public void writeToParcel(@NonNull Parcel dest, int flags) {
CREATOR.writeToParcel(this, dest, flags);
}
public static final SafeParcelableCreatorAndWriter<ClearExportRequest> CREATOR = findCreator(ClearExportRequest.class);
}

View file

@ -0,0 +1,53 @@
/*
* SPDX-FileCopyrightText: 2026 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.identitycredentials;
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;
/**
* Response of a registry deletion operation.
*/
@SafeParcelable.Class
public class ClearExportResponse extends AbstractSafeParcelable {
@Field(value = 1, getterName = "isDeleted")
private final boolean isDeleted;
/**
* constructs an instance of {@link ClearExportResponse}
*
* @param isDeleted if true, indicates clear operation deleted some registries, otherwise indicates there was no data to delete; unexpected failures will be thrown as exceptions
*/
@Constructor
public ClearExportResponse(@Param(1) boolean isDeleted) {
this.isDeleted = isDeleted;
}
/**
* if true, indicates clear operation deleted some registries, otherwise indicates there was no data to delete; unexpected failures will be thrown as exceptions
*/
public final boolean isDeleted() {
return this.isDeleted;
}
@Override
public void writeToParcel(@NonNull Parcel dest, int flags) {
CREATOR.writeToParcel(this, dest, flags);
}
public static final SafeParcelableCreatorAndWriter<ClearExportResponse> CREATOR = findCreator(ClearExportResponse.class);
}

View file

@ -0,0 +1,155 @@
/*
* SPDX-FileCopyrightText: 2026 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.identitycredentials;
import android.os.Parcel;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
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 java.util.List;
/**
* A request to clear the registries stored for your app.
* <p>
* The order of the conditions are important. If {@code deleteAll} is true, then the other conditions are ignored, and all the registries for your app that
* was registered with the {@link IdentityCredentialClient#registerCredentials} API are deleted.
*/
@SafeParcelable.Class
public class ClearRegistryRequest extends AbstractSafeParcelable {
@Field(value = 1, getterName = "getDeleteAll", defaultValue = "true")
private final boolean deleteAll;
@Field(value = 2, getterName = "getClearTypedRegistryOption")
@Nullable
private final ClearTypedRegistryOption clearTypedRegistryOption;
/**
* Cosntructs a request to clear all registries for your app that was registered with the IdentityCredentials.registerCredentials API.
*/
public ClearRegistryRequest() {
this(true, null);
}
/**
* constructs an instance of {@link ClearRegistryRequest}
*
* @param deleteAll whether to delete all registries for your app
* @param clearTypedRegistryOption an option to clear the registries for a given type that matches the RegistrationRequest.type provided during registration
*/
@Constructor
public ClearRegistryRequest(@Param(1) boolean deleteAll, @Param(2) @Nullable ClearTypedRegistryOption clearTypedRegistryOption) {
this.deleteAll = deleteAll;
this.clearTypedRegistryOption = clearTypedRegistryOption;
}
/**
* whether to delete all registries for your app
*/
public final boolean getDeleteAll() {
return this.deleteAll;
}
/**
* an option to clear the registries for a given type that matches the RegistrationRequest.type provided during registration
*/
@Nullable
public final ClearTypedRegistryOption getClearTypedRegistryOption() {
return this.clearTypedRegistryOption;
}
@Override
public void writeToParcel(@NonNull Parcel dest, int flags) {
CREATOR.writeToParcel(this, dest, flags);
}
public static final SafeParcelableCreatorAndWriter<ClearRegistryRequest> CREATOR = findCreator(ClearRegistryRequest.class);
/**
* A request to configure how to clear the registries for a given type.
* <p>
* The order of the conditions are important. If {@code deleteAllForType} is true, then the other conditions are ignored and all the registries for the
* given type are deleted. Otherwise, if {@code deleteIdlessRegistry} is true, then the registry with an empty ID is deleted; at the same time, the
* registries with the IDs provided in {@code registryIds} will also be deleted.
*/
public static class ClearTypedRegistryOption extends AbstractSafeParcelable {
@Field(value = 1, getterName = "getDeleteAllForType")
private final boolean deleteAllForType;
@Field(value = 2, getterName = "getType")
@NonNull
private final String type;
@Field(value = 3, getterName = "getDeleteIdlessRegistry")
private final boolean deleteIdlessRegistry;
@Field(value = 4, getterName = "getRegistryIds")
@NonNull
private final List<String> registryIds;
/**
* constructs an instance of {@link ClearTypedRegistryOption}
*
* @param deleteAllForType whether to delete all registries for the given type
* @param type the type of registry to clear, matching the RegistrationRequest.type provided during registration
* @param deleteIdlessRegistry whether to delete the registry for the given type that was registered without an ID provided; in other words, the registry that was registered without providing RegistrationRequest.id
* @param registryIds the IDs of the registries for the given type to delete
*/
@Constructor
public ClearTypedRegistryOption(@Param(1) boolean deleteAllForType, @NonNull @Param(2) String type, @Param(3) boolean deleteIdlessRegistry, @NonNull @Param(4) List<String> registryIds) {
this.deleteAllForType = deleteAllForType;
this.type = type;
this.deleteIdlessRegistry = deleteIdlessRegistry;
this.registryIds = registryIds;
}
/**
* whether to delete all registries for the given type
*/
public final boolean getDeleteAllForType() {
return this.deleteAllForType;
}
/**
* whether to delete the registry for the given type that was registered without an ID provided; in other words, the registry that was registered without providing RegistrationRequest.id
*/
public final boolean getDeleteIdlessRegistry() {
return this.deleteIdlessRegistry;
}
/**
* the IDs of the registries for the given type to delete
*/
@NonNull
public final List<String> getRegistryIds() {
return this.registryIds;
}
/**
* the type of registry to clear, matching the RegistrationRequest.type provided during registration
*/
@NonNull
public final String getType() {
return this.type;
}
@Override
public void writeToParcel(@NonNull Parcel dest, int flags) {
CREATOR.writeToParcel(this, dest, flags);
}
public static final SafeParcelableCreatorAndWriter<ClearTypedRegistryOption> CREATOR = findCreator(ClearTypedRegistryOption.class);
}
}

View file

@ -0,0 +1,50 @@
/*
* SPDX-FileCopyrightText: 2026 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.identitycredentials;
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;
/**
* Response of a registry deletion operation.
*/
@SafeParcelable.Class
public class ClearRegistryResponse extends AbstractSafeParcelable {
@Field(value = 1, getterName = "isDeleted")
private final boolean isDeleted;
/**
* constructs an instance of {@link ClearRegistryResponse}
*
* @param isDeleted if true, indicates clear operation deleted some registries, otherwise indicates there was no data to delete; unexpected failures will be thrown as exceptions
*/
@Constructor
public ClearRegistryResponse(@Param(1) boolean isDeleted) {
this.isDeleted = isDeleted;
}
/**
* if true, indicates clear operation deleted some registries, otherwise indicates there was no data to delete; unexpected failures will be thrown as exceptions
*/
public final boolean isDeleted() {
return this.isDeleted;
}
@Override
public void writeToParcel(@NonNull Parcel dest, int flags) {
CREATOR.writeToParcel(this, dest, flags);
}
public static final SafeParcelableCreatorAndWriter<ClearRegistryResponse> CREATOR = findCreator(ClearRegistryResponse.class);
}

View file

@ -0,0 +1,71 @@
/*
* SPDX-FileCopyrightText: 2026 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.identitycredentials;
import android.app.PendingIntent;
import android.os.Parcel;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
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;
/**
* Returns a response for the {@link IdentityCredentialClient#createCredential} API that can be used to launch the credential selector UIs to
* finalize on a credential of the user's choice that can be used for app sign-in, or the actual credential response itself if no UI is needed.
*/
@SafeParcelable.Class
public class CreateCredentialHandle extends AbstractSafeParcelable {
@Field(value = 1, getterName = "getPendingIntent")
@Nullable
private final PendingIntent pendingIntent;
@Field(value = 2, getterName = "getCreateCredentialResponse")
@Nullable
private final CreateCredentialResponse createCredentialResponse;
/**
* constructs an instance of {@link CreateCredentialHandle}
*
* @param pendingIntent the {@link PendingIntent} to launch the credential selector UI
* @param createCredentialResponse the {@link CreateCredentialResponse} if no UI is needed
*/
@Constructor
public CreateCredentialHandle(@Param(1) @Nullable PendingIntent pendingIntent, @Param(2) @Nullable CreateCredentialResponse createCredentialResponse) {
if (pendingIntent == null && createCredentialResponse == null) {
throw new IllegalArgumentException("pendingIntent or createCredentialResponse must be specified.");
}
this.pendingIntent = pendingIntent;
this.createCredentialResponse = createCredentialResponse;
}
/**
* the {@link CreateCredentialResponse} if no UI is needed
*/
@Nullable
public CreateCredentialResponse getCreateCredentialResponse() {
return createCredentialResponse;
}
/**
* the {@link PendingIntent} to launch the credential selector UI
*/
@Nullable
public PendingIntent getPendingIntent() {
return pendingIntent;
}
@Override
public void writeToParcel(@NonNull Parcel dest, int flags) {
CREATOR.writeToParcel(this, dest, flags);
}
public static final SafeParcelableCreatorAndWriter<CreateCredentialHandle> CREATOR = findCreator(CreateCredentialHandle.class);
}

View file

@ -0,0 +1,112 @@
/*
* SPDX-FileCopyrightText: 2026 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.identitycredentials;
import android.os.Bundle;
import android.os.Parcel;
import android.os.ResultReceiver;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
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;
/**
* Data interface for creating or saving a user credential.
*/
@SafeParcelable.Class
public class CreateCredentialRequest extends AbstractSafeParcelable {
@Field(value = 1, getterName = "getType")
@NonNull
private final String type;
@Field(value = 2, getterName = "getCredentialData")
@NonNull
private final Bundle credentialData;
@Field(value = 3, getterName = "getCandidateQueryData")
@NonNull
private final Bundle candidateQueryData;
@Field(value = 4, getterName = "getOrigin")
@Nullable
private final String origin;
@Field(value = 5, getterName = "getRequestJson")
@Nullable
private final String requestJson;
@Field(value = 6, getterName = "getResultReceiver")
@Nullable
private final ResultReceiver resultReceiver;
/**
* constructs an instance of {@link CreateCredentialRequest}
*
* @param type the type of the credential to be created or saved
* @param credentialData the complete request data in {@link Bundle} format, consisting of all the data that will be sent to the provider during the final credential creation stage
* @param candidateQueryData the partial request data in {@link Bundle} format, that will be sent to the provider during the initial candidate query stage, which will not contain sensitive user information
* @param origin the origin of the request, only settable by a browser
*/
@Constructor
public CreateCredentialRequest(@Param(1) @NonNull String type, @Param(2) @NonNull Bundle credentialData, @Param(3) @NonNull Bundle candidateQueryData, @Param(4) @Nullable String origin, @Param(5) @Nullable String requestJson, @Param(6) @Nullable ResultReceiver resultReceiver) {
this.type = type;
this.credentialData = credentialData;
this.candidateQueryData = candidateQueryData;
this.origin = origin;
this.requestJson = requestJson;
this.resultReceiver = resultReceiver;
}
/**
* the partial request data in {@link Bundle} format, that will be sent to the provider during the initial candidate query stage, which will not contain sensitive user information
*/
@NonNull
public Bundle getCandidateQueryData() {
return candidateQueryData;
}
/**
* the complete request data in {@link Bundle} format, consisting of all the data that will be sent to the provider during the final credential creation stage
*/
@NonNull
public Bundle getCredentialData() {
return credentialData;
}
/**
* the origin of the request, only settable by a browser
*/
@Nullable
public String getOrigin() {
return origin;
}
@Nullable
public String getRequestJson() {
return requestJson;
}
@Nullable
public ResultReceiver getResultReceiver() {
return resultReceiver;
}
/**
* the type of the credential to be created or saved
*/
@NonNull
public String getType() {
return type;
}
@Override
public void writeToParcel(@NonNull Parcel dest, int flags) {
CREATOR.writeToParcel(this, dest, flags);
}
public static final SafeParcelableCreatorAndWriter<CreateCredentialRequest> CREATOR = findCreator(CreateCredentialRequest.class);
}

View file

@ -0,0 +1,63 @@
/*
* SPDX-FileCopyrightText: 2026 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.identitycredentials;
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;
/**
* Data interface for the response of creating or saving a user credential.
*/
@SafeParcelable.Class
public class CreateCredentialResponse extends AbstractSafeParcelable {
@Field(value = 1, getterName = "getType")
@NonNull
public final String type;
@Field(value = 2, getterName = "getData")
@NonNull
public final Bundle data;
/**
* constructs an instance of {@link CreateCredentialResponse}
*/
@Constructor
public CreateCredentialResponse(@Param(1) @NonNull String type, @Param(2) @NonNull Bundle data) {
this.type = type;
this.data = data;
}
/**
* the data of the credential that was created or saved, in the form of a {@link Bundle}
*/
@NonNull
public Bundle getData() {
return data;
}
/**
* the type of the credential that was created or saved
*/
@NonNull
public String getType() {
return type;
}
@Override
public void writeToParcel(@NonNull Parcel dest, int flags) {
CREATOR.writeToParcel(this, dest, flags);
}
public static final SafeParcelableCreatorAndWriter<CreateCredentialResponse> CREATOR = findCreator(CreateCredentialResponse.class);
}

View file

@ -0,0 +1,65 @@
/*
* SPDX-FileCopyrightText: 2026 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.identitycredentials;
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;
/**
* Represents a user credential that can be used to authenticate to your app.
*/
@SafeParcelable.Class
public class Credential extends AbstractSafeParcelable {
@Field(value = 1, getterName = "getType")
@NonNull
public final String type;
@Field(value = 2, getterName = "getData")
@NonNull
public final Bundle data;
/**
* constructs an instance of Credential
* @param type the type of the credential
* @param data the data associated with the credential
*/
@Constructor
public Credential(@Param(1) @NonNull String type, @Param(2) @NonNull Bundle data) {
this.type = type;
this.data = data;
}
/**
* the data associated with the credential
*/
@NonNull
public Bundle getData() {
return data;
}
/**
* the type of the credential
*/
@NonNull
public String getType() {
return type;
}
@Override
public void writeToParcel(@NonNull Parcel dest, int flags) {
CREATOR.writeToParcel(this, dest, flags);
}
public static final SafeParcelableCreatorAndWriter<Credential> CREATOR = findCreator(Credential.class);
}

View file

@ -0,0 +1,70 @@
/*
* SPDX-FileCopyrightText: 2026 microG Project Team
* SPDX-License-Identifier: Apache-2.0
*/
package com.google.android.gms.identitycredentials;
import android.os.Parcel;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
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;
@SafeParcelable.Class
@Hide
public class CredentialInformation extends AbstractSafeParcelable {
@Field(value = 1, getterName = "getPackageName")
@Nullable
private final String packageName;
@Field(value = 2, getterName = "getNumPasswordCredentials")
private final int numPasswordCredentials;
@Field(value = 3, getterName = "getNumPasskeyCredentials")
private final int numPasskeyCredentials;
@Field(value = 4, getterName = "getNumGoogleIdCredentials")
private final int numGoogleIdCredentials;
@Field(value = 5, getterName = "getNumCustomCredentials")
private final int numCustomCredentials;
@Constructor
public CredentialInformation(@Param(1) @Nullable String packageName, @Param(2) int numPasswordCredentials, @Param(3) int numPasskeyCredentials, @Param(4) int numGoogleIdCredentials, @Param(5) int numCustomCredentials) {
this.packageName = packageName;
this.numPasswordCredentials = numPasswordCredentials;
this.numPasskeyCredentials = numPasskeyCredentials;
this.numGoogleIdCredentials = numGoogleIdCredentials;
this.numCustomCredentials = numCustomCredentials;
}
@Nullable
public String getPackageName() {
return packageName;
}
public int getNumPasswordCredentials() {
return numPasswordCredentials;
}
public int getNumPasskeyCredentials() {
return numPasskeyCredentials;
}
public int getNumGoogleIdCredentials() {
return numGoogleIdCredentials;
}
public int getNumCustomCredentials() {
return numCustomCredentials;
}
@Override
public void writeToParcel(@NonNull Parcel dest, int flags) {
CREATOR.writeToParcel(this, dest, flags);
}
public static final SafeParcelableCreatorAndWriter<CredentialInformation> CREATOR = findCreator(CredentialInformation.class);
}

View file

@ -0,0 +1,39 @@
/*
* SPDX-FileCopyrightText: 2026 microG Project Team
* SPDX-License-Identifier: Apache-2.0
*/
package com.google.android.gms.identitycredentials;
import android.os.Parcel;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
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 java.util.List;
@SafeParcelable.Class
@Hide
public class CredentialInformationRequest extends AbstractSafeParcelable {
@Field(1)
@Nullable
public final List<String> packageNames;
@Constructor
public CredentialInformationRequest(@Param(1) @Nullable List<String> packageNames) {
this.packageNames = packageNames;
}
@Override
public void writeToParcel(@NonNull Parcel dest, int flags) {
CREATOR.writeToParcel(this, dest, flags);
}
public static final SafeParcelableCreatorAndWriter<CredentialInformationRequest> CREATOR = findCreator(CredentialInformationRequest.class);
}

View file

@ -0,0 +1,44 @@
/*
* SPDX-FileCopyrightText: 2026 microG Project Team
* SPDX-License-Identifier: Apache-2.0
*/
package com.google.android.gms.identitycredentials;
import android.os.Parcel;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
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 java.util.List;
@SafeParcelable.Class
@Hide
public class CredentialInformationResponse extends AbstractSafeParcelable {
@Field(value = 1, getterName = "getCredentialInformationList")
@Nullable
private final List<CredentialInformation> credentialInformationList;
@Constructor
public CredentialInformationResponse(@Param(1) @Nullable List<CredentialInformation> credentialInformationList) {
this.credentialInformationList = credentialInformationList;
}
@Nullable
public List<CredentialInformation> getCredentialInformationList() {
return credentialInformationList;
}
@Override
public void writeToParcel(@NonNull Parcel dest, int flags) {
CREATOR.writeToParcel(this, dest, flags);
}
public static final SafeParcelableCreatorAndWriter<CredentialInformationResponse> CREATOR = findCreator(CredentialInformationResponse.class);
}

View file

@ -0,0 +1,115 @@
/*
* SPDX-FileCopyrightText: 2026 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.identitycredentials;
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;
/**
* Base class for getting a specific type of credentials.
* <p>
* {@link GetCredentialRequest} will be composed of a list of {@link CredentialOption} subclasses to indicate the specific credential types and
* configurations that your app accepts.
*/
@SafeParcelable.Class
public class CredentialOption extends AbstractSafeParcelable {
@Field(value = 1, getterName = "getType")
private final String type;
@Field(value = 2, getterName = "getCredentialRetrievalData")
private final Bundle credentialRetrievalData;
@Field(value = 3, getterName = "getCandidateQueryData")
private final Bundle candidateQueryData;
@Field(value = 4, getterName = "getRequestMatcher")
private final String requestMatcher;
@Field(value = 5, getterName = "getRequestType")
@Deprecated
private final String requestType;
@Field(value = 6, getterName = "getProtocolType")
@Deprecated
private final String protocolType;
/**
* constructs an instance of {@link CredentialOption}
*
* @param type the type of the credential to be requested
* @param credentialRetrievalData the retrieval data in {@link Bundle} format
* @param candidateQueryData the partial request data in the {@link Bundle} format that will be sent to the provider during the initial candidate query stage, which will not contain sensitive user information
* @param requestMatcher the criteria used to filter the request (for instance, age 21)
* @param requestType deprecated
* @param protocolType deprecated
*/
@Constructor
public CredentialOption(@Param(1) String type, @Param(2) Bundle credentialRetrievalData, @Param(3) Bundle candidateQueryData, @Param(4) String requestMatcher, @Deprecated @Param(5) String requestType, @Deprecated @Param(6) String protocolType) {
this.type = type;
this.credentialRetrievalData = credentialRetrievalData;
this.candidateQueryData = candidateQueryData;
this.requestMatcher = requestMatcher;
this.requestType = requestType;
this.protocolType = protocolType;
}
/**
* the partial request data in the {@link Bundle} format that will be sent to the provider during the initial candidate query stage, which will not contain sensitive user information
*/
public Bundle getCandidateQueryData() {
return candidateQueryData;
}
/**
* the retrieval data in {@link Bundle} format
*/
public Bundle getCredentialRetrievalData() {
return credentialRetrievalData;
}
/**
* @deprecated
*/
@Deprecated
public String getProtocolType() {
return protocolType;
}
/**
* the criteria used to filter the request (for instance, age 21)
*/
public String getRequestMatcher() {
return requestMatcher;
}
/**
* @deprecated
*/
@Deprecated
public String getRequestType() {
return requestType;
}
/**
* the type of the credential to be requested
*/
public String getType() {
return type;
}
@Override
public void writeToParcel(@NonNull Parcel dest, int flags) {
CREATOR.writeToParcel(this, dest, flags);
}
public static final SafeParcelableCreatorAndWriter<CredentialOption> CREATOR = findCreator(CredentialOption.class);
}

View file

@ -0,0 +1,107 @@
/*
* SPDX-FileCopyrightText: 2026 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.identitycredentials;
import android.os.Bundle;
import android.os.Parcel;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
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;
/**
* The state of the primary provider's credentials
*/
@SafeParcelable.Class
public class CredentialTransferCapabilities extends AbstractSafeParcelable {
@Field(value = 1, getterName = "getResponseBundle")
private final Bundle responseBundle;
@Constructor
public CredentialTransferCapabilities(@Param(1) Bundle responseBundle) {
this.responseBundle = responseBundle;
}
/**
* Returns the number of requested credentials.
*/
@Nullable
public final Integer getNumCustomCredentials(@NonNull String key) {
if (this.responseBundle.containsKey(key)) {
return this.responseBundle.getInt(key);
}
return null;
}
/**
* Returns the number of passkeys.
*/
@Nullable
public final Integer getNumPasskeys() {
if (this.responseBundle.containsKey("NUM_PASSKEYS")) {
return this.responseBundle.getInt("NUM_PASSKEYS");
}
return null;
}
/**
* Returns the number of passwords.
*/
@Nullable
public final Integer getNumPasswords() {
if (this.responseBundle.containsKey("NUM_PASSWORDS")) {
return this.responseBundle.getInt("NUM_PASSWORDS");
}
return null;
}
@Nullable
public final CallingAppInfoParcelable getProviderAppInfo() {
return (CallingAppInfoParcelable) this.responseBundle.getParcelable("PROVIDER_APP_INFO");
}
/**
* the bundle containing the credential transfer capabilities.
*/
public Bundle getResponseBundle() {
return responseBundle;
}
/**
* Returns the total number of credentials.
*/
@Nullable
public final Integer getTotalNumCredentials() {
if (this.responseBundle.containsKey("TOTAL_NUM_CREDENTIALS")) {
return this.responseBundle.getInt("TOTAL_NUM_CREDENTIALS");
}
return null;
}
/**
* Returns the total size of credentials in bytes.
*/
@Nullable
public final Long getTotalSizeBytes() {
if (this.responseBundle.containsKey("TOTAL_SIZE_BYTES")) {
return this.responseBundle.getLong("TOTAL_SIZE_BYTES");
}
return null;
}
@Override
public void writeToParcel(@NonNull Parcel dest, int flags) {
CREATOR.writeToParcel(this, dest, flags);
}
public static final SafeParcelableCreatorAndWriter<CredentialTransferCapabilities> CREATOR = findCreator(CredentialTransferCapabilities.class);
}

View file

@ -0,0 +1,65 @@
/*
* SPDX-FileCopyrightText: 2026 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.identitycredentials;
import android.net.Uri;
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;
/**
* Request for exporting credentials to primary credential provider.
*/
@SafeParcelable.Class
public class ExportCredentialsToDeviceSetupRequest extends AbstractSafeParcelable {
@Field(value = 1, getterName = "getUri")
@NonNull
private final Uri uri;
@Field(value = 2, getterName = "getRequestData")
@NonNull
private final Bundle requestData;
/**
* @param uri the file URI responsible for the export transport. The export provider will write the credentials here.
* @param requestData the request bundle
*/
@Constructor
public ExportCredentialsToDeviceSetupRequest(@NonNull @Param(1) Uri uri, @NonNull @Param(2) Bundle requestData) {
this.uri = uri;
this.requestData = requestData;
}
/**
* the request bundle
*/
@NonNull
public Bundle getRequestData() {
return requestData;
}
/**
* the file URI responsible for the export transport. The export provider will write the credentials here.
*/
@NonNull
public Uri getUri() {
return uri;
}
@Override
public void writeToParcel(@NonNull Parcel dest, int flags) {
CREATOR.writeToParcel(this, dest, flags);
}
public static final SafeParcelableCreatorAndWriter<ExportCredentialsToDeviceSetupRequest> CREATOR = findCreator(ExportCredentialsToDeviceSetupRequest.class);
}

View file

@ -0,0 +1,105 @@
/*
* SPDX-FileCopyrightText: 2026 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.identitycredentials;
import android.os.Bundle;
import android.os.Parcel;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
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;
/**
* Response for exporting the credentials to the primary provider
*/
@SafeParcelable.Class
public class ExportCredentialsToDeviceSetupResponse extends AbstractSafeParcelable {
@Field(1)
@NonNull
public final Bundle responseBundle;
/**
* @param responseBundle the bundle containing response extras.
*/
@Constructor
public ExportCredentialsToDeviceSetupResponse(@NonNull @Param(1) Bundle responseBundle) {
this.responseBundle = responseBundle;
}
/**
* Returns the number of credentials failed to stored.
*
* @deprecated
*/
@Deprecated
@Nullable
public final Integer getNumFailure() {
if (this.responseBundle.containsKey("NUM_FAILURE")) {
return this.responseBundle.getInt("NUM_FAILURE");
}
return null;
}
/**
* Returns the number of credentials that were ignored by the provider.
*
* @deprecated
*/
@Deprecated
@Nullable
public final Integer getNumIgnored() {
if (this.responseBundle.containsKey("NUM_IGNORED")) {
return this.responseBundle.getInt("NUM_IGNORED");
}
return null;
}
/**
* Returns the number of credentials successfully stored.
*
* @deprecated
*/
@Deprecated
@Nullable
public final Integer getNumSuccess() {
if (this.responseBundle.containsKey("NUM_SUCCESS")) {
return this.responseBundle.getInt("NUM_SUCCESS");
}
return null;
}
/**
* Returns the provider app info.
*
* @deprecated
*/
@Deprecated
@Nullable
public final CallingAppInfoParcelable getProviderAppInfo() {
return this.responseBundle.getParcelable("PROVIDER_APP_INFO");
}
/**
* the bundle containing response extras.
*/
@NonNull
public Bundle getResponseBundle() {
return responseBundle;
}
@Override
public void writeToParcel(@NonNull Parcel dest, int flags) {
CREATOR.writeToParcel(this, dest, flags);
}
public static final SafeParcelableCreatorAndWriter<ExportCredentialsToDeviceSetupResponse> CREATOR = findCreator(ExportCredentialsToDeviceSetupResponse.class);
}

View file

@ -0,0 +1,98 @@
/*
* SPDX-FileCopyrightText: 2026 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.identitycredentials;
import android.os.Bundle;
import android.os.Parcel;
import android.os.ResultReceiver;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
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 java.util.List;
/**
* Data interface for retrieving a user credential.
*/
@SafeParcelable.Class
public class GetCredentialRequest extends AbstractSafeParcelable {
@Field(value = 1, getterName = "getCredentialOptions")
@NonNull
private final List<CredentialOption> credentialOptions;
@Field(value = 2, getterName = "getData")
@NonNull
private final Bundle data;
@Field(value = 3, getterName = "getOrigin")
@Nullable
private final String origin;
@Field(value = 4, getterName = "getResultReceiver")
@Deprecated
@NonNull
private final ResultReceiver resultReceiver;
/**
* constructs an instance of {@link GetCredentialRequest}
*
* @param credentialOptions the list of credential options
* @param data the additional data to be used for retrieving the credential
* @param origin the origin of the request, only settable by a browser
* @param resultReceiver deprecated
*/
@Constructor
public GetCredentialRequest(@NonNull @Param(1) List<CredentialOption> credentialOptions, @NonNull @Param(2) Bundle data, @Nullable @Param(3) String origin, @Deprecated @NonNull @Param(4) ResultReceiver resultReceiver) {
this.credentialOptions = credentialOptions;
this.data = data;
this.origin = origin;
this.resultReceiver = resultReceiver;
}
/**
* the list of credential options
*/
@NonNull
public List<CredentialOption> getCredentialOptions() {
return credentialOptions;
}
/**
* the additional data to be used for retrieving the credential
*/
@NonNull
public Bundle getData() {
return data;
}
/**
* the origin of the request, only settable by a browser
*/
@Nullable
public String getOrigin() {
return origin;
}
/**
* @deprecated
*/
@Deprecated
@NonNull
public ResultReceiver getResultReceiver() {
return resultReceiver;
}
@Override
public void writeToParcel(@NonNull Parcel dest, int flags) {
CREATOR.writeToParcel(this, dest, flags);
}
public static final SafeParcelableCreatorAndWriter<GetCredentialRequest> CREATOR = findCreator(GetCredentialRequest.class);
}

View file

@ -0,0 +1,49 @@
/*
* SPDX-FileCopyrightText: 2026 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.identitycredentials;
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;
/**
* Request for fetching the state of the credentials in the primary provider
*/
@SafeParcelable.Class
public class GetCredentialTransferCapabilitiesRequest extends AbstractSafeParcelable {
@Field(value = 1, getterName = "getRequestData")
private final Bundle requestData;
/**
* @param requestData the request bundle
*/
@Constructor
public GetCredentialTransferCapabilitiesRequest(@Param(1) Bundle requestData) {
this.requestData = requestData;
}
/**
* the request bundle
*/
public Bundle getRequestData() {
return requestData;
}
@Override
public void writeToParcel(@NonNull Parcel dest, int flags) {
CREATOR.writeToParcel(this, dest, flags);
}
public static final SafeParcelableCreatorAndWriter<GetCredentialTransferCapabilitiesRequest> CREATOR = findCreator(GetCredentialTransferCapabilitiesRequest.class);
}

View file

@ -0,0 +1,119 @@
/*
* SPDX-FileCopyrightText: 2026 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.identitycredentials;
import androidx.annotation.NonNull;
import com.google.android.gms.common.api.Api;
import com.google.android.gms.common.api.HasApiKey;
import com.google.android.gms.tasks.Task;
/**
* A client for the Identity Credentials API.
*/
public interface IdentityCredentialClient extends HasApiKey<Api.ApiOptions.NoOptions> {
/**
* Returns a {@link Task} which asynchronously generates a {@link ClearCreationOptionsResponse} on success or throws an {@code ApiException} on failure,
* when attempting to clear from the creation option registry that should match one registered with {@link IdentityCredentialClient#registerCreationOptions}.
*
* @param request informs the type of operation
*/
@NonNull
Task<ClearCreationOptionsResponse> clearCreationOptions(@NonNull ClearCreationOptionsRequest request);
/**
* Returns a {@link Task} which asynchronously generates a {@link ClearCredentialStateResponse} on success or throws an {@code ApiException} on failure,
* when attempting to clear credential state.
*
* @param request specifies the clear credential state request
*/
@NonNull
Task<ClearCredentialStateResponse> clearCredentialState(@NonNull ClearCredentialStateRequest request);
/**
* Returns a {@link Task} which asynchronously generates a {@link ClearExportResponse} on success or throws an {@code ApiException} on failure, when
* attempting to clear from the registry.
*
* @param request informs the type of operation
*/
@NonNull
Task<ClearExportResponse> clearExport(@NonNull ClearExportRequest request);
/**
* Returns a {@link Task} which asynchronously generates a {@link ClearRegistryResponse} on success or throws an {@code ApiException} on failure, when attempting to clear from the registry.
*
* @param request informs the type of operation
*/
@NonNull
Task<ClearRegistryResponse> clearRegistry(@NonNull ClearRegistryRequest request);
/**
* Returns a {@link Task} which asynchronously generates a {@link CreateCredentialHandle} on success or throws an {@code ApiException} on failure.
*
* @param request containing parameters of the credential to be created
*/
@NonNull
Task<CreateCredentialHandle> createCredential(@NonNull CreateCredentialRequest request);
/**
* Returns a {@link Task} which asynchronously generates a {@link PendingGetCredentialHandle} on success or throws an {@code ApiException} on failure.
*
* @param request the request for getting the credential
*/
@NonNull
Task<PendingGetCredentialHandle> getCredential(@NonNull GetCredentialRequest request);
/**
* Returns a {@link Task} which asynchronously generates a {@link PendingImportCredentialsHandle} on success or throws an {@code ApiException} on failure.
*
* @param request the information needed to import credentials from another provider
*/
@NonNull
Task<PendingImportCredentialsHandle> importCredentials(@NonNull ImportCredentialsRequest request);
/**
* Register the creation options that may serve a {@link IdentityCredentialClient#createCredential} transaction.
* <p>
* Returns a {@link Task} which asynchronously generates a {@link RegisterCreationOptionsResponse} on success or throws an {@code ApiException} on
* failure, when attempting to write to the registry.
*
* @param request specifies the credential information being written to the registry
*/
@NonNull
Task<RegisterCreationOptionsResponse> registerCreationOptions(@NonNull RegisterCreationOptionsRequest request);
/**
* RRegister the credential options that may serve a {@link IdentityCredentialClient#getCredential} transaction.
* <p>
* Returns a {@link Task} which asynchronously generates a {@link RegistrationResponse} on success or throws an {@code ApiException} on failure, when
* attempting to write to the registry.
*
* @param request specifies the credential information being written to the registry
*/
@NonNull
Task<RegistrationResponse> registerCredentials(@NonNull RegistrationRequest request);
/**
* Returns a {@link Task} which asynchronously generates a {@link RegisterExportResponse} on success or throws an {@code ApiException} on failure, when
* attempting to write to the registry.
*
* @param request specifies the information being written to the registry
*/
@NonNull
Task<RegisterExportResponse> registerExport(@NonNull RegisterExportRequest request);
/**
* Returns a {@link Task} which asynchronously generates a {@link SignalCredentialStateResponse} on success or throws an {@code ApiException} on failure,
* when attempting to signal providers with credential state.
*
* @param request specifies the signal credential state request
*/
@NonNull
Task<SignalCredentialStateResponse> signalCredentialState(@NonNull SignalCredentialStateRequest request);
}

View file

@ -0,0 +1,42 @@
/*
* SPDX-FileCopyrightText: 2026 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.identitycredentials;
import android.app.Activity;
import android.content.Context;
import androidx.annotation.NonNull;
import org.microg.gms.identitycredentials.IdentityCredentialClientImpl;
/**
* Entry point for Identity Credential API.
*/
public final class IdentityCredentialManager {
/**
* Creates a new instance of {@link IdentityCredentialClient}.
*
* @param activity the activity that is using this client.
*/
@NonNull
public static IdentityCredentialClient getClient(@NonNull Activity activity) {
return new IdentityCredentialClientImpl(activity);
}
/**
* Creates a new instance of {@link IdentityCredentialClient}.
*
* @param context the context that is using this client.
*/
@NonNull
public static IdentityCredentialClient getClient(@NonNull Context context) {
return new IdentityCredentialClientImpl(context);
}
private IdentityCredentialManager() {
}
}

View file

@ -0,0 +1,78 @@
/*
* SPDX-FileCopyrightText: 2026 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.identitycredentials;
import android.net.Uri;
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;
/**
* Request for importing credentials from primary credential provider.
*/
@SafeParcelable.Class
public class ImportCredentialsForDeviceSetupRequest extends AbstractSafeParcelable {
@Field(value = 1, getterName = "getRequestJson")
@NonNull
private final String requestJson;
@Field(value = 2, getterName = "getUri")
@NonNull
private final Uri uri;
@Field(value = 3, getterName = "getRequestData")
@NonNull
private final Bundle requestData;
/**
* @param requestJson the request in JSON format, based on the CXF prototcol
* @param uri the file URI responsible for the credential transport. The importing provider will read the credentials from here.
* @param requestData the request bundle
*/
@Constructor
public ImportCredentialsForDeviceSetupRequest(@NonNull @Param(1) String requestJson, @NonNull @Param(2) Uri uri, @NonNull @Param(3) Bundle requestData) {
this.requestJson = requestJson;
this.uri = uri;
this.requestData = requestData;
}
/**
* the request bundle
*/
@NonNull
public Bundle getRequestData() {
return requestData;
}
/**
* the request in JSON format, based on the CXF prototcol
*/
@NonNull
public String getRequestJson() {
return requestJson;
}
/**
* the file URI responsible for the credential transport. The importing provider will read the credentials from here.
*/
@NonNull
public Uri getUri() {
return uri;
}
@Override
public void writeToParcel(@NonNull Parcel dest, int flags) {
CREATOR.writeToParcel(this, dest, flags);
}
public static final SafeParcelableCreatorAndWriter<ImportCredentialsForDeviceSetupRequest> CREATOR = findCreator(ImportCredentialsForDeviceSetupRequest.class);
}

View file

@ -0,0 +1,60 @@
/*
* SPDX-FileCopyrightText: 2026 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.identitycredentials;
import android.os.Bundle;
import android.os.Parcel;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
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;
/**
* Response for importing the credentials from the primary provider
*/
@SafeParcelable.Class
public class ImportCredentialsForDeviceSetupResponse extends AbstractSafeParcelable {
@Field(value = 1, getterName = "getResponseBundle")
@NonNull
private final Bundle responseBundle;
/**
* @param responseBundle the bundle containing response extras.
*/
@Constructor
public ImportCredentialsForDeviceSetupResponse(@NonNull @Param(1) Bundle responseBundle) {
this.responseBundle = responseBundle;
}
/**
* the bundle containing response extras.
*/
@NonNull
public Bundle getResponseBundle() {
return responseBundle;
}
/**
* Returns the provider app info.
*/
@Nullable
public final CallingAppInfoParcelable getProviderAppInfo() {
return this.responseBundle.getParcelable("PROVIDER_APP_INFO");
}
@Override
public void writeToParcel(@NonNull Parcel dest, int flags) {
CREATOR.writeToParcel(this, dest, flags);
}
public static final SafeParcelableCreatorAndWriter<ImportCredentialsForDeviceSetupResponse> CREATOR = findCreator(ImportCredentialsForDeviceSetupResponse.class);
}

View file

@ -0,0 +1,66 @@
/*
* SPDX-FileCopyrightText: 2026 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.identitycredentials;
import android.net.Uri;
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;
/**
* Request for importing credentials from another credential provider.
*/
@SafeParcelable.Class
public class ImportCredentialsRequest extends AbstractSafeParcelable {
@NonNull
public static final String REQUEST_TYPE = "androidx.identitycredentials.TYPE_CREDENTIALS_SYNC";
@Field(value = 1, getterName = "getRequestJson")
@NonNull
private final String requestJson;
@Field(value = 2, getterName = "getUri")
@NonNull
private final Uri uri;
/**
* @param requestJson the request in JSON format, based on the CXF prototcol
* @param uri the file URI responsible for the export transport
*/
@Constructor
public ImportCredentialsRequest(@NonNull @Param(1) String requestJson, @NonNull @Param(2) Uri uri) {
this.requestJson = requestJson;
this.uri = uri;
}
/**
* the request in JSON format, based on the CXF prototcol
*/
@NonNull
public final String getRequestJson() {
return this.requestJson;
}
/**
* the file URI responsible for the export transport
*/
@NonNull
public final Uri getUri() {
return this.uri;
}
@Override
public void writeToParcel(@NonNull Parcel dest, int flags) {
CREATOR.writeToParcel(this, dest, flags);
}
public static final SafeParcelableCreatorAndWriter<ImportCredentialsRequest> CREATOR = findCreator(ImportCredentialsRequest.class);
}

View file

@ -0,0 +1,54 @@
/*
* SPDX-FileCopyrightText: 2026 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.identitycredentials;
import android.app.PendingIntent;
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;
/**
* Returns a response for the {@link IdentityCredentialClient#getCredential} API that can be used to launch the credential selector UIs to
* finalize on a credential of the user's choice that can be used for app sign-in.
*/
@SafeParcelable.Class
public class PendingGetCredentialHandle extends AbstractSafeParcelable {
@Field(value = 1, getterName = "getPendingIntent")
@NonNull
private final PendingIntent pendingIntent;
/**
* constructs an instance of {@link PendingGetCredentialHandle}
*
* @param pendingIntent the {@link PendingIntent} to launch the credential selector UI
*/
@Constructor
public PendingGetCredentialHandle(@NonNull @Param(1) PendingIntent pendingIntent) {
this.pendingIntent = pendingIntent;
}
/**
* the {@link PendingIntent} to launch the credential selector UI
*/
@NonNull
public PendingIntent getPendingIntent() {
return pendingIntent;
}
@Override
public void writeToParcel(@NonNull Parcel dest, int flags) {
CREATOR.writeToParcel(this, dest, flags);
}
public static final SafeParcelableCreatorAndWriter<PendingGetCredentialHandle> CREATOR = findCreator(PendingGetCredentialHandle.class);
}

View file

@ -0,0 +1,52 @@
/*
* SPDX-FileCopyrightText: 2026 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.identitycredentials;
import android.app.PendingIntent;
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;
/**
* Response to {@link IdentityCredentialClient#importCredentials} API, containing a {@link PendingIntent} that can be used to launch a selector
* that allows the user to select a credential provider to import credentials from
*/
@SafeParcelable.Class
public class PendingImportCredentialsHandle extends AbstractSafeParcelable {
@Field(value = 1, getterName = "getPendingIntent")
@NonNull
private final PendingIntent pendingIntent;
/**
* @param pendingIntent the intent that launches the selector UI
*/
@Constructor
public PendingImportCredentialsHandle(@NonNull @Param(1) PendingIntent pendingIntent) {
this.pendingIntent = pendingIntent;
}
/**
* the intent that launches the selector UI
*/
@NonNull
public PendingIntent getPendingIntent() {
return pendingIntent;
}
@Override
public void writeToParcel(@NonNull Parcel dest, int flags) {
CREATOR.writeToParcel(this, dest, flags);
}
public static final SafeParcelableCreatorAndWriter<PendingImportCredentialsHandle> CREATOR = findCreator(PendingImportCredentialsHandle.class);
}

View file

@ -0,0 +1,109 @@
/*
* SPDX-FileCopyrightText: 2026 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.identitycredentials;
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;
/**
* A registration request to store provision / creation candidates' metadata and matcher logic.
*/
@SafeParcelable.Class
public class RegisterCreationOptionsRequest extends AbstractSafeParcelable {
@Field(value = 1, getterName = "getCreateOptions")
@NonNull
private final byte[] createOptions;
@Field(value = 2, getterName = "getMatcher")
@NonNull
private final byte[] matcher;
@Field(value = 3, getterName = "getType")
@NonNull
private final String type;
@Field(value = 4, getterName = "getId")
@NonNull
private final String id;
@Field(value = 5, getterName = "getFulfillmentActionName", defaultValue = "")
@NonNull
private final String fulfillmentActionName;
/**
* constructs an instance of {@link RegisterCreationOptionsRequest}
*
* @param createOptions the creation candidates data used for display and matching purpose, as a ByteArray blob
* @param matcher the matcher for the credential info, as a ByteArray blob
* @param type the type of the creation options registered, matching the {@code CreateCredentialRequest.type} that this registry can handle
* @param id the id of the given registry data, so as not to overwrite existing data of different id
* @param fulfillmentActionName optionally specify a different intent action to be used for launching the fulfillment activity when one of the registered credentials is selected by the user; otherwise, the default action {@code "androidx.credentials.registry.provider.action.CREATE_CREDENTIAL"} will be used
*/
@Constructor
public RegisterCreationOptionsRequest(@NonNull @Param(1) byte[] createOptions, @NonNull @Param(2) byte[] matcher, @NonNull @Param(3) String type, @NonNull @Param(4) String id, @NonNull @Param(5) String fulfillmentActionName) {
this.createOptions = createOptions;
this.matcher = matcher;
this.type = type;
this.id = id;
this.fulfillmentActionName = fulfillmentActionName;
}
/**
* the creation candidates data used for display and matching purpose, as a ByteArray blob
*/
@NonNull
public byte[] getCreateOptions() {
return createOptions;
}
/**
* optionally specify a different intent action to be used for launching the fulfillment activity when one of the registered credentials is selected
* by the user; otherwise, the default action {@code "androidx.credentials.registry.provider.action.CREATE_CREDENTIAL"} will be used
*/
@NonNull
public String getFulfillmentActionName() {
return fulfillmentActionName;
}
/**
* the id of the given registry data, so as not to overwrite existing data of different id
*/
@NonNull
public String getId() {
return id;
}
/**
* the matcher for the credential info, as a ByteArray blob
*/
@NonNull
public byte[] getMatcher() {
return matcher;
}
/**
* the type of the creation options registered, matching the {@code CreateCredentialRequest.type} that this registry can handle
*/
@NonNull
public String getType() {
return type;
}
@Override
public void writeToParcel(@NonNull Parcel dest, int flags) {
CREATOR.writeToParcel(this, dest, flags);
}
public static final SafeParcelableCreatorAndWriter<RegisterCreationOptionsRequest> CREATOR = findCreator(RegisterCreationOptionsRequest.class);
}

View file

@ -0,0 +1,31 @@
/*
* SPDX-FileCopyrightText: 2026 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.identitycredentials;
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;
/**
* Response object for the {@link IdentityCredentialClient#registerCredentials} API.
*/
@SafeParcelable.Class
public class RegisterCreationOptionsResponse extends AbstractSafeParcelable {
@Override
public void writeToParcel(@NonNull Parcel dest, int flags) {
CREATOR.writeToParcel(this, dest, flags);
}
public static final SafeParcelableCreatorAndWriter<RegisterCreationOptionsResponse> CREATOR = findCreator(RegisterCreationOptionsResponse.class);
}

View file

@ -0,0 +1,79 @@
/*
* SPDX-FileCopyrightText: 2026 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.identitycredentials;
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;
/**
* A registration request for declaring that the callee is a credential provider that supports exporting of credentials to other credential providers
*/
@SafeParcelable.Class
public class RegisterExportRequest extends AbstractSafeParcelable {
@NonNull
public static final String REQUEST_TYPE = "androidx.identitycredentials.TYPE_CREDENTIALS_SYNC";
@Field(value = 1, getterName = "getMatcher")
@NonNull
private final byte[] matcher;
@Field(value = 2, getterName = "getData")
@NonNull
private final byte[] data;
@Field(value = 3, getterName = "getId")
@NonNull
private final String id;
/**
* @param matcher the matcher executor that runs the matching logic
* @param data any data to be registered along with the ability to export, typically empty for this use-case
* @param id the ID of the given registry data, so as not to overwrite existing data of different ID
*/
@Constructor
public RegisterExportRequest(@NonNull @Param(1) byte[] matcher, @NonNull @Param(2) byte[] data, @NonNull @Param(3) String id) {
this.matcher = matcher;
this.data = data;
this.id = id;
}
/**
* any data to be registered along with the ability to export, typically empty for this use-case
*/
@NonNull
public byte[] getData() {
return data;
}
/**
* the ID of the given registry data, so as not to overwrite existing data of different ID
*/
@NonNull
public String getId() {
return id;
}
/**
* the matcher executor that runs the matching logic
*/
@NonNull
public byte[] getMatcher() {
return matcher;
}
@Override
public void writeToParcel(@NonNull Parcel dest, int flags) {
CREATOR.writeToParcel(this, dest, flags);
}
public static final SafeParcelableCreatorAndWriter<RegisterExportRequest> CREATOR = findCreator(RegisterExportRequest.class);
}

View file

@ -0,0 +1,31 @@
/*
* SPDX-FileCopyrightText: 2026 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.identitycredentials;
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;
/**
* Response for registering the ability to export credentials to other providers
*/
@SafeParcelable.Class
public class RegisterExportResponse extends AbstractSafeParcelable {
@Override
public void writeToParcel(@NonNull Parcel dest, int flags) {
CREATOR.writeToParcel(this, dest, flags);
}
public static final SafeParcelableCreatorAndWriter<RegisterExportResponse> CREATOR = findCreator(RegisterExportResponse.class);
}

View file

@ -0,0 +1,142 @@
/*
* SPDX-FileCopyrightText: 2026 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.identitycredentials;
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 java.util.List;
/**
* A registration request to store credential metadata and matcher logic.
*/
@SafeParcelable.Class
public class RegistrationRequest extends AbstractSafeParcelable {
@Field(value = 1, getterName = "getCredentials")
@NonNull
private final byte[] credentials;
@Field(value = 2, getterName = "getMatcher")
@NonNull
private final byte[] matcher;
@Field(value = 3, getterName = "getType", defaultValue = "\"\"")
@NonNull
private final String type;
@Field(value = 4, getterName = "getRequestType", defaultValue = "\"\"")
@NonNull
@Deprecated
private final String requestType;
@Field(value = 5, getterName = "getProtocolTypes", defaultValue = "java.util.Collections.emptyList()")
@NonNull
@Deprecated
private final List<String> protocolTypes;
@Field(value = 6, getterName = "getId", defaultValue = "\"\"")
@NonNull
private final String id;
@Field(value = 7, getterName = "getFulfillmentActionName", defaultValue = "\"\"")
@NonNull
private final String fulfillmentActionName;
public RegistrationRequest(@NonNull byte[] credentials, @NonNull byte[] matcher, @NonNull String type, @Deprecated @NonNull String requestType, @Deprecated @NonNull List<String> protocolTypes) {
this(credentials, matcher, type, requestType, protocolTypes, "", "");
}
/**
* constructs an instance of {@link RegistrationRequest}
*
* @param credentials the credential information as a ByteArray blob
* @param matcher the matcher for the credential info, also as a ByteArray blob
* @param type the type of credentials matching the given registry data
* @param requestType deprecated
* @param protocolTypes deprecated
* @param id the id of the given registry data, so as not to overwrite existing data of different id
* @param fulfillmentActionName optionally specify a different intent action to be used for launching the fulfillment activity when one of the registered credentials is selected by the user; otherwise, the default action {@code "androidx.credentials.registry.provider.action.GET_CREDENTIAL"} will be used
*/
@Constructor
public RegistrationRequest(@NonNull @Param(1) byte[] credentials, @NonNull @Param(2) byte[] matcher, @NonNull @Param(3) String type, @Deprecated @NonNull @Param(4) String requestType, @Deprecated @NonNull @Param(5) List<String> protocolTypes, @NonNull @Param(6) String id, @NonNull @Param(7) String fulfillmentActionName) {
this.credentials = credentials;
this.matcher = matcher;
this.type = type;
this.requestType = requestType;
this.protocolTypes = protocolTypes;
this.id = id;
this.fulfillmentActionName = fulfillmentActionName;
}
/**
* the credential information as a ByteArray blob
*/
@NonNull
public byte[] getCredentials() {
return credentials;
}
/**
* optionally specify a different intent action to be used for launching the fulfillment activity when one of the registered credentials is selected
* by the user; otherwise, the default action {@code "androidx.credentials.registry.provider.action.GET_CREDENTIAL"} will be used
*/
@NonNull
public String getFulfillmentActionName() {
return fulfillmentActionName;
}
/**
* the id of the given registry data, so as not to overwrite existing data of different id
*/
@NonNull
public String getId() {
return id;
}
/**
* the matcher for the credential info, also as a ByteArray blob
*/
@NonNull
public byte[] getMatcher() {
return matcher;
}
/**
* @deprecated
*/
@Deprecated
@NonNull
public List<String> getProtocolTypes() {
return protocolTypes;
}
/**
* @deprecated
*/
@Deprecated
@NonNull
public String getRequestType() {
return requestType;
}
/**
* the type of credentials matching the given registry data
*/
@NonNull
public String getType() {
return type;
}
@Override
public void writeToParcel(@NonNull Parcel dest, int flags) {
CREATOR.writeToParcel(this, dest, flags);
}
public static final SafeParcelableCreatorAndWriter<RegistrationRequest> CREATOR = findCreator(RegistrationRequest.class);
}

View file

@ -0,0 +1,31 @@
/*
* SPDX-FileCopyrightText: 2026 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.identitycredentials;
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;
/**
* Response object for the IdentityCredentialClient.registerCredentials API.
*/
@SafeParcelable.Class
public class RegistrationResponse extends AbstractSafeParcelable {
@Override
public void writeToParcel(@NonNull Parcel dest, int flags) {
CREATOR.writeToParcel(this, dest, flags);
}
public static final SafeParcelableCreatorAndWriter<RegistrationResponse> CREATOR = findCreator(RegistrationResponse.class);
}

View file

@ -0,0 +1,82 @@
/*
* SPDX-FileCopyrightText: 2026 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.identitycredentials;
import android.os.Bundle;
import android.os.Parcel;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
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;
/**
* Data interface for signaling a user's credential state from the RPs to the credential providers.
*/
@SafeParcelable.Class
public class SignalCredentialStateRequest extends AbstractSafeParcelable {
@Field(value = 1, getterName = "getType")
@NonNull
private final String type;
@Field(value = 2, getterName = "getOrigin")
@Nullable
private final String origin;
@Field(value = 3, getterName = "getRequestData")
@NonNull
private final Bundle requestData;
/**
* constructs an instance of {@link SignalCredentialStateRequest}
*
* @param type the type of signal request being sent to the provider
* @param origin the origin of the request, only settable by a browser
* @param requestData the request data, containing the credential state information
*/
@Constructor
public SignalCredentialStateRequest(@NonNull @Param(1) String type, @Param(2) @Nullable String origin, @NonNull @Param(3) Bundle requestData) {
this.type = type;
this.origin = origin;
this.requestData = requestData;
}
/**
* the origin of the request, only settable by a browser
*/
@Nullable
public String getOrigin() {
return origin;
}
/**
* the request data, containing the credential state information
*/
@NonNull
public Bundle getRequestData() {
return requestData;
}
/**
* the type of signal request being sent to the provider
*/
@NonNull
public String getType() {
return type;
}
@Override
public void writeToParcel(@NonNull Parcel dest, int flags) {
CREATOR.writeToParcel(this, dest, flags);
}
public static final SafeParcelableCreatorAndWriter<SignalCredentialStateRequest> CREATOR = findCreator(SignalCredentialStateRequest.class);
}

View file

@ -0,0 +1,31 @@
/*
* SPDX-FileCopyrightText: 2026 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.identitycredentials;
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;
/**
* Response of a signal credential state request.
*/
@SafeParcelable.Class
public class SignalCredentialStateResponse extends AbstractSafeParcelable {
@Override
public void writeToParcel(@NonNull Parcel dest, int flags) {
CREATOR.writeToParcel(this, dest, flags);
}
public static final SafeParcelableCreatorAndWriter<SignalCredentialStateResponse> CREATOR = findCreator(SignalCredentialStateResponse.class);
}

View file

@ -0,0 +1,145 @@
/*
* SPDX-FileCopyrightText: 2026 microG Project Team
* SPDX-License-Identifier: Apache-2.0
*/
package org.microg.gms.identitycredentials;
import android.content.Context;
import android.os.IBinder;
import android.os.RemoteException;
import com.google.android.gms.common.api.Api;
import com.google.android.gms.common.api.ApiMetadata;
import com.google.android.gms.common.api.Status;
import com.google.android.gms.common.api.internal.ConnectionCallbacks;
import com.google.android.gms.common.api.internal.OnConnectionFailedListener;
import com.google.android.gms.identitycredentials.ClearCreationOptionsRequest;
import com.google.android.gms.identitycredentials.ClearCredentialStateRequest;
import com.google.android.gms.identitycredentials.ClearExportRequest;
import com.google.android.gms.identitycredentials.ClearRegistryRequest;
import com.google.android.gms.identitycredentials.CreateCredentialRequest;
import com.google.android.gms.identitycredentials.GetCredentialRequest;
import com.google.android.gms.identitycredentials.ImportCredentialsRequest;
import com.google.android.gms.identitycredentials.RegisterCreationOptionsRequest;
import com.google.android.gms.identitycredentials.RegisterExportRequest;
import com.google.android.gms.identitycredentials.RegistrationRequest;
import com.google.android.gms.identitycredentials.SignalCredentialStateRequest;
import com.google.android.gms.identitycredentials.internal.IIdentityCredentialCallbacks;
import com.google.android.gms.identitycredentials.internal.IIdentityCredentialService;
import org.microg.gms.common.GmsClient;
import org.microg.gms.common.GmsService;
public class IdentityCredentialApiClient extends GmsClient<IIdentityCredentialService> {
public static final Api<Api.ApiOptions.NoOptions> API = new Api<>(
(options, context, looper, clientSettings, callbacks, connectionFailedListener) ->
new IdentityCredentialApiClient(context, callbacks, connectionFailedListener));
public IdentityCredentialApiClient(Context context, ConnectionCallbacks callbacks, OnConnectionFailedListener connectionFailedListener) {
super(context, callbacks, connectionFailedListener, GmsService.IDENTITY_CREDENTIALS.ACTION);
serviceId = GmsService.IDENTITY_CREDENTIALS.SERVICE_ID;
}
@Override
protected IIdentityCredentialService interfaceFromBinder(IBinder binder) {
return IIdentityCredentialService.Stub.asInterface(binder);
}
public void getCredential(IIdentityCredentialCallbacks callbacks, GetCredentialRequest request) {
try {
getServiceInterface().getCredential(callbacks, request, ApiMetadata.SKIP);
} catch (RemoteException e) {
tryNotifyError(() -> callbacks.onGetCredential(Status.INTERNAL_ERROR, null, ApiMetadata.SKIP));
}
}
public void registerCredentials(IIdentityCredentialCallbacks callbacks, RegistrationRequest request) {
try {
getServiceInterface().register(callbacks, request, ApiMetadata.SKIP);
} catch (RemoteException e) {
tryNotifyError(() -> callbacks.onRegister(Status.INTERNAL_ERROR, null, ApiMetadata.SKIP));
}
}
public void clearRegistry(IIdentityCredentialCallbacks callbacks, ClearRegistryRequest request) {
try {
getServiceInterface().clearRegistry(callbacks, request, ApiMetadata.SKIP);
} catch (RemoteException e) {
tryNotifyError(() -> callbacks.onClearRegistry(Status.INTERNAL_ERROR, null, ApiMetadata.SKIP));
}
}
public void importCredentials(IIdentityCredentialCallbacks callbacks, ImportCredentialsRequest request) {
try {
getServiceInterface().importCredentials(callbacks, request, ApiMetadata.SKIP);
} catch (RemoteException e) {
tryNotifyError(() -> callbacks.onImportCredentials(Status.INTERNAL_ERROR, null, ApiMetadata.SKIP));
}
}
public void registerExport(IIdentityCredentialCallbacks callbacks, RegisterExportRequest request) {
try {
getServiceInterface().registerExport(callbacks, request, ApiMetadata.SKIP);
} catch (RemoteException e) {
tryNotifyError(() -> callbacks.onRegisterExport(Status.INTERNAL_ERROR, null, ApiMetadata.SKIP));
}
}
public void createCredential(IIdentityCredentialCallbacks callbacks, CreateCredentialRequest request) {
try {
getServiceInterface().createCredential(callbacks, request, ApiMetadata.SKIP);
} catch (RemoteException e) {
tryNotifyError(() -> callbacks.onCreateCredential(Status.INTERNAL_ERROR, null, ApiMetadata.SKIP));
}
}
public void registerCreationOptions(IIdentityCredentialCallbacks callbacks, RegisterCreationOptionsRequest request) {
try {
getServiceInterface().registerCreationOptions(callbacks, request, ApiMetadata.SKIP);
} catch (RemoteException e) {
tryNotifyError(() -> callbacks.onRegisterCreationOptions(Status.INTERNAL_ERROR, null, ApiMetadata.SKIP));
}
}
public void clearCredentialState(IIdentityCredentialCallbacks callbacks, ClearCredentialStateRequest request) {
try {
getServiceInterface().clearCredentialState(callbacks, request, ApiMetadata.SKIP);
} catch (RemoteException e) {
tryNotifyError(() -> callbacks.onClearCredentialState(Status.INTERNAL_ERROR, null, ApiMetadata.SKIP));
}
}
public void signalCredentialState(IIdentityCredentialCallbacks callbacks, SignalCredentialStateRequest request) {
try {
getServiceInterface().signalCredentialState(callbacks, request, ApiMetadata.SKIP);
} catch (RemoteException e) {
tryNotifyError(() -> callbacks.onSignalCredentialState(Status.INTERNAL_ERROR, null, ApiMetadata.SKIP));
}
}
public void clearExport(IIdentityCredentialCallbacks callbacks, ClearExportRequest request) {
try {
getServiceInterface().clearExport(callbacks, request, ApiMetadata.SKIP);
} catch (RemoteException e) {
tryNotifyError(() -> callbacks.onClearExport(Status.INTERNAL_ERROR, null, ApiMetadata.SKIP));
}
}
public void clearCreationOptions(IIdentityCredentialCallbacks callbacks, ClearCreationOptionsRequest request) {
try {
getServiceInterface().clearCreationOptions(callbacks, request, ApiMetadata.SKIP);
} catch (RemoteException e) {
tryNotifyError(() -> callbacks.onClearCreationOptions(Status.INTERNAL_ERROR, null, ApiMetadata.SKIP));
}
}
private interface RemoteRunnable {
void run() throws RemoteException;
}
private static void tryNotifyError(RemoteRunnable runnable) {
try {
runnable.run();
} catch (RemoteException ignored) {
}
}
}

View file

@ -0,0 +1,212 @@
/*
* SPDX-FileCopyrightText: 2026 microG Project Team
* SPDX-License-Identifier: Apache-2.0
*/
package org.microg.gms.identitycredentials;
import android.content.Context;
import androidx.annotation.NonNull;
import com.google.android.gms.common.api.Api;
import com.google.android.gms.common.api.ApiException;
import com.google.android.gms.common.api.ApiMetadata;
import com.google.android.gms.common.api.GoogleApi;
import com.google.android.gms.common.api.Status;
import com.google.android.gms.identitycredentials.ClearCreationOptionsRequest;
import com.google.android.gms.identitycredentials.ClearCreationOptionsResponse;
import com.google.android.gms.identitycredentials.ClearCredentialStateRequest;
import com.google.android.gms.identitycredentials.ClearCredentialStateResponse;
import com.google.android.gms.identitycredentials.ClearExportRequest;
import com.google.android.gms.identitycredentials.ClearExportResponse;
import com.google.android.gms.identitycredentials.ClearRegistryRequest;
import com.google.android.gms.identitycredentials.ClearRegistryResponse;
import com.google.android.gms.identitycredentials.CreateCredentialHandle;
import com.google.android.gms.identitycredentials.CreateCredentialRequest;
import com.google.android.gms.identitycredentials.CreateCredentialResponse;
import com.google.android.gms.identitycredentials.CredentialInformationResponse;
import com.google.android.gms.identitycredentials.CredentialTransferCapabilities;
import com.google.android.gms.identitycredentials.ExportCredentialsToDeviceSetupResponse;
import com.google.android.gms.identitycredentials.GetCredentialRequest;
import com.google.android.gms.identitycredentials.IdentityCredentialClient;
import com.google.android.gms.identitycredentials.ImportCredentialsForDeviceSetupResponse;
import com.google.android.gms.identitycredentials.ImportCredentialsRequest;
import com.google.android.gms.identitycredentials.PendingGetCredentialHandle;
import com.google.android.gms.identitycredentials.PendingImportCredentialsHandle;
import com.google.android.gms.identitycredentials.RegisterCreationOptionsRequest;
import com.google.android.gms.identitycredentials.RegisterCreationOptionsResponse;
import com.google.android.gms.identitycredentials.RegisterExportRequest;
import com.google.android.gms.identitycredentials.RegisterExportResponse;
import com.google.android.gms.identitycredentials.RegistrationRequest;
import com.google.android.gms.identitycredentials.RegistrationResponse;
import com.google.android.gms.identitycredentials.SignalCredentialStateRequest;
import com.google.android.gms.identitycredentials.SignalCredentialStateResponse;
import com.google.android.gms.identitycredentials.internal.IIdentityCredentialCallbacks;
import com.google.android.gms.tasks.Task;
import com.google.android.gms.tasks.TaskCompletionSource;
import org.microg.gms.common.api.PendingGoogleApiCall;
public class IdentityCredentialClientImpl extends GoogleApi<Api.ApiOptions.NoOptions> implements IdentityCredentialClient {
public IdentityCredentialClientImpl(Context context) {
super(context, IdentityCredentialApiClient.API, Api.ApiOptions.NO_OPTIONS);
}
@NonNull
@Override
public Task<ClearCreationOptionsResponse> clearCreationOptions(@NonNull ClearCreationOptionsRequest request) {
return scheduleTask((PendingGoogleApiCall<ClearCreationOptionsResponse, IdentityCredentialApiClient>) (client, source) ->
client.clearCreationOptions(new BaseCallbacks() {
@Override
public void onClearCreationOptions(Status status, ClearCreationOptionsResponse response, ApiMetadata apiMetadata) {
complete(source, status, response);
}
}, request));
}
@NonNull
@Override
public Task<ClearCredentialStateResponse> clearCredentialState(@NonNull ClearCredentialStateRequest request) {
return scheduleTask((PendingGoogleApiCall<ClearCredentialStateResponse, IdentityCredentialApiClient>) (client, source) ->
client.clearCredentialState(new BaseCallbacks() {
@Override
public void onClearCredentialState(Status status, ClearCredentialStateResponse response, ApiMetadata apiMetadata) {
complete(source, status, response);
}
}, request));
}
@NonNull
@Override
public Task<ClearExportResponse> clearExport(@NonNull ClearExportRequest request) {
return scheduleTask((PendingGoogleApiCall<ClearExportResponse, IdentityCredentialApiClient>) (client, source) ->
client.clearExport(new BaseCallbacks() {
@Override
public void onClearExport(Status status, ClearExportResponse response, ApiMetadata apiMetadata) {
complete(source, status, response);
}
}, request));
}
@NonNull
@Override
public Task<ClearRegistryResponse> clearRegistry(@NonNull ClearRegistryRequest request) {
return scheduleTask((PendingGoogleApiCall<ClearRegistryResponse, IdentityCredentialApiClient>) (client, source) ->
client.clearRegistry(new BaseCallbacks() {
@Override
public void onClearRegistry(Status status, ClearRegistryResponse response, ApiMetadata apiMetadata) {
complete(source, status, response);
}
}, request));
}
@NonNull
@Override
public Task<CreateCredentialHandle> createCredential(@NonNull CreateCredentialRequest request) {
return scheduleTask((PendingGoogleApiCall<CreateCredentialHandle, IdentityCredentialApiClient>) (client, source) ->
client.createCredential(new BaseCallbacks() {
@Override
public void onCreateCredential(Status status, CreateCredentialHandle handle, ApiMetadata apiMetadata) {
complete(source, status, handle);
}
}, request));
}
@NonNull
@Override
public Task<PendingGetCredentialHandle> getCredential(@NonNull GetCredentialRequest request) {
return scheduleTask((PendingGoogleApiCall<PendingGetCredentialHandle, IdentityCredentialApiClient>) (client, source) ->
client.getCredential(new BaseCallbacks() {
@Override
public void onGetCredential(Status status, PendingGetCredentialHandle handle, ApiMetadata apiMetadata) {
complete(source, status, handle);
}
}, request));
}
@NonNull
@Override
public Task<PendingImportCredentialsHandle> importCredentials(@NonNull ImportCredentialsRequest request) {
return scheduleTask((PendingGoogleApiCall<PendingImportCredentialsHandle, IdentityCredentialApiClient>) (client, source) ->
client.importCredentials(new BaseCallbacks() {
@Override
public void onImportCredentials(Status status, PendingImportCredentialsHandle handle, ApiMetadata apiMetadata) {
complete(source, status, handle);
}
}, request));
}
@NonNull
@Override
public Task<RegisterCreationOptionsResponse> registerCreationOptions(@NonNull RegisterCreationOptionsRequest request) {
return scheduleTask((PendingGoogleApiCall<RegisterCreationOptionsResponse, IdentityCredentialApiClient>) (client, source) ->
client.registerCreationOptions(new BaseCallbacks() {
@Override
public void onRegisterCreationOptions(Status status, RegisterCreationOptionsResponse response, ApiMetadata apiMetadata) {
complete(source, status, response);
}
}, request));
}
@NonNull
@Override
public Task<RegistrationResponse> registerCredentials(@NonNull RegistrationRequest request) {
return scheduleTask((PendingGoogleApiCall<RegistrationResponse, IdentityCredentialApiClient>) (client, source) ->
client.registerCredentials(new BaseCallbacks() {
@Override
public void onRegister(Status status, RegistrationResponse response, ApiMetadata apiMetadata) {
complete(source, status, response);
}
}, request));
}
@NonNull
@Override
public Task<RegisterExportResponse> registerExport(@NonNull RegisterExportRequest request) {
return scheduleTask((PendingGoogleApiCall<RegisterExportResponse, IdentityCredentialApiClient>) (client, source) ->
client.registerExport(new BaseCallbacks() {
@Override
public void onRegisterExport(Status status, RegisterExportResponse response, ApiMetadata apiMetadata) {
complete(source, status, response);
}
}, request));
}
@NonNull
@Override
public Task<SignalCredentialStateResponse> signalCredentialState(@NonNull SignalCredentialStateRequest request) {
return scheduleTask((PendingGoogleApiCall<SignalCredentialStateResponse, IdentityCredentialApiClient>) (client, source) ->
client.signalCredentialState(new BaseCallbacks() {
@Override
public void onSignalCredentialState(Status status, SignalCredentialStateResponse response, ApiMetadata apiMetadata) {
complete(source, status, response);
}
}, request));
}
private static <T> void complete(TaskCompletionSource<T> source, Status status, T result) {
if (status != null && status.isSuccess()) {
source.trySetResult(result);
} else {
source.trySetException(new ApiException(status == null ? Status.INTERNAL_ERROR : status));
}
}
// Empty defaults so each scheduleTask can override only the relevant callback.
private static abstract class BaseCallbacks extends IIdentityCredentialCallbacks.Stub {
@Override public void onGetCredential(Status status, PendingGetCredentialHandle handle, ApiMetadata apiMetadata) {}
@Override public void onRegister(Status status, RegistrationResponse response, ApiMetadata apiMetadata) {}
@Override public void onClearRegistry(Status status, ClearRegistryResponse response, ApiMetadata apiMetadata) {}
@Override public void onImportCredentials(Status status, PendingImportCredentialsHandle handle, ApiMetadata apiMetadata) {}
@Override public void onRegisterExport(Status status, RegisterExportResponse response, ApiMetadata apiMetadata) {}
@Override public void onCreateCredentialLegacy(Status status, CreateCredentialResponse response, ApiMetadata apiMetadata) {}
@Override public void onCreateCredential(Status status, CreateCredentialHandle handle, ApiMetadata apiMetadata) {}
@Override public void onRegisterCreationOptions(Status status, RegisterCreationOptionsResponse response, ApiMetadata apiMetadata) {}
@Override public void onClearCredentialState(Status status, ClearCredentialStateResponse response, ApiMetadata apiMetadata) {}
@Override public void onSignalCredentialState(Status status, SignalCredentialStateResponse response, ApiMetadata apiMetadata) {}
@Override public void onClearExport(Status status, ClearExportResponse response, ApiMetadata apiMetadata) {}
@Override public void onImportCredentialsForDeviceSetup(Status status, ImportCredentialsForDeviceSetupResponse response, ApiMetadata apiMetadata) {}
@Override public void onExportCredentialsToDeviceSetup(Status status, ExportCredentialsToDeviceSetupResponse response, ApiMetadata apiMetadata) {}
@Override public void onGetCredentialTransferCapabilities(Status status, CredentialTransferCapabilities capabilities, ApiMetadata apiMetadata) {}
@Override public void onClearCreationOptions(Status status, ClearCreationOptionsResponse response, ApiMetadata apiMetadata) {}
@Override public void onGetCredentialInformation(Status status, CredentialInformationResponse response) {}
}
}

View file

@ -43,6 +43,7 @@ include ':play-services-fido'
include ':play-services-games'
include ':play-services-gcm'
include ':play-services-gmscompliance'
include ':play-services-identity-credentials'
include ':play-services-iid'
include ':play-services-location'
include ':play-services-maps'
@ -98,6 +99,7 @@ sublude ':play-services-droidguard:core'
sublude ':play-services-fido:core'
sublude ':play-services-fitness:core'
sublude ':play-services-gmscompliance:core'
sublude ':play-services-identity-credentials:core'
sublude ':play-services-location:core'
sublude ':play-services-location:core:base'
sublude ':play-services-location:core:provider'