I'm making a android game with java, using CredentialManager to prompt the user to choose a Google account.
My code works but when the user taps outside the prompt, the prompt closes, but the OnCancelListener
callback isn't invoked, nor is onResult
or onError
.
public void signIn_credentialManager() {
String nonce = randomNonce();
GetCredentialRequest request;
googleIdOption = new GetGoogleIdOption.Builder()
.setFilterByAuthorizedAccounts(false)
.setServerClientId("...")
.setAutoSelectEnabled(true)
.setNonce(nonce)
.build();
request = new GetCredentialRequest.Builder()
.addCredentialOption(googleIdOption)
.build();
CancellationSignal cancellationSignal = new CancellationSignal();
cancellationSignal.setOnCancelListener(new CancellationSignal.OnCancelListener() {
@Override
public void onCancel() {
// HERE NEVER TRIGGERED!
log(LOG_TAG, "credentialManager.getCredentialAsync onCancel");
}
});
cancellationSignal.throwIfCanceled();
log(LOG_TAG, "credentialManager.getCredentialAsync");
credentialManager.getCredentialAsync(
context,
request,
cancellationSignal,
executor,
new CredentialManagerCallback<GetCredentialResponse, GetCredentialException>() {
@Override
public void onResult(GetCredentialResponse result) {
log(LOG_TAG, "CredentialManagerCallback onResult");
try {
...
}
catch (Exception e) {
log(LOG_TAG, "CredentialManagerCallback Exception!");
e.printStackTrace();
}
}
@Override
public void onError(@NonNull GetCredentialException e) {
log(LOG_TAG, "CredentialManagerCallback Error!");
e.printStackTrace();
}
}
);
}
build.gradle (Android module):
plugins {
id "org.jetbrains.kotlin.android" version "1.9.24" apply false
}
apply plugin: 'com.android.application'
apply plugin: 'com.google.gms.google-services'
apply plugin: 'com.google.firebase.crashlytics'
android {
compileSdk 35
sourceSets {
main {
manifest.srcFile 'AndroidManifest.xml'
java.srcDirs('src/main/java')
aidl.srcDirs('src/main/java')
renderscript.srcDirs('src/main/java')
res.srcDirs('res')
assets.srcDirs('../assets')
jniLibs.srcDirs('libs')
}
}
packagingOptions {
resources.with {
excludes += ['META-INF/robovm/ios/robovm.xml',
'META-INF/DEPENDENCIES.txt', 'META-INF/DEPENDENCIES', 'META-INF/dependencies.txt', '**/*.gwt.xml']
pickFirsts += ['META-INF/LICENSE.txt', 'META-INF/LICENSE', 'META-INF/license.txt', 'META-INF/LGPL2.1',
'META-INF/NOTICE.txt', 'META-INF/NOTICE', 'META-INF/notice.txt']
}
}
defaultConfig {
applicationId 'app.mywebsite.myappname'
minSdkVersion 24
targetSdkVersion 35
versionCode 1
versionName "1.0.0 test"
// multiDexEnabled true
}
namespace "app.mywebsite.myappname"
compileOptions {
sourceCompatibility "11"
targetCompatibility "11"
coreLibraryDesugaringEnabled true
}
buildTypes {
debug {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
debuggable true
}
release {
minifyEnabled true
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
debuggable false
}
}
buildFeatures {
buildConfig = true
}
}
repositories {
google()
}
configurations { natives }
dependencies {
coreLibraryDesugaring 'com.android.tools:desugar_jdk_libs:2.1.5'
implementation "com.badlogicgames.gdx:gdx-backend-android:$gdxVersion"
implementation project(':core')
natives "com.badlogicgames.gdx:..."
implementation 'androidx.appcompat:appcompat:1.7.0'
implementation 'androidx.legacy:legacy-support-v4:1.0.0'
implementation platform('com.google.firebase:firebase-bom:33.10.0')
implementation 'com.google.firebase:firebase-crashlytics:19.4.1'
implementation 'com.google.firebase:firebase-analytics:22.3.0'
implementation "androidx.credentials:credentials:1.5.0"
implementation "androidx.credentials:credentials-play-services-auth:1.5.0"
implementation "com.google.android.libraries.identity.googleid:googleid:1.1.1"
implementation "com.google.android.gms:play-services-games-v2:20.1.2"
implementation 'com.google.android.gms:play-services-auth:21.3.0'
}
tasks.register('run', Exec) {
def path
def localProperties = project.file("../local.properties")
if (localProperties.exists()) {
Properties properties = new Properties()
localProperties.withInputStream { instr ->
properties.load(instr)
}
def sdkDir = properties.getProperty('sdk.dir')
if (sdkDir) {
path = sdkDir
} else {
path = "$System.env.ANDROID_SDK_ROOT"
}
} else {
path = "$System.env.ANDROID_SDK_ROOT"
}
def adb = path + "/platform-tools/adb"
commandLine "$adb", 'shell', 'am', 'start', '-n', 'app.mywebsite.myappname/app.mywebsite.myappname.android.MainActivity'
}
eclipse.project.name = appName + "-android"
Maybe CancellationSignal.onCancel
is triggered only it I explicitely call .cancel
on the request, if so how to handle the dismiss?
I also noticed that if the user click on "cancel" in that google prompt, the GetCredentialCancellationException
will be thrown, so I would expect the same exception if the user touches outside that prompt, but instead it does not happen.
I'm using a Samsung Galaxy M53 5G with Android 14, Google Play system update May 1, 2024 and One UI version 6.0.
Edit:
I tried on my Samsung Galaxy Tab A (2018, 10.5) with Android 10 and One UI 2.1 and it throws GetCredentialCancellationException
as expected.
What version of Android are you testing that on? Tapping outside of the bottomsheet should call CredentialManagerCallback#onError(exception)
and you should get the GetCredentialException
exception with the message: "User cancelled the selector"; I just tested that on Android 15 and that is what I got:
androidx.credentials.exceptions.GetCredentialCancellationException: User cancelled the selector