I am trying to access a Google Drive account content from Android, using the GoogleDriveApi for Android and Groovy. But I get a stange error in the logcat, about a ClassCastException with the DriveApi class, though I followed official Google tutorial, but with the Groovy language. (In order to simplify the problem, I've created a small project that reproduces the same error as in my original one.)
This is the build gradle (the project has been generated from command line : there is a unique gradle.build file. Submitting this gradle build is a way for me to give you dependencies in a simple way)
buildscript {
repositories {
jcenter()
}
dependencies {
classpath 'com.android.tools.build:gradle:1.5.0'
classpath 'org.codehaus.groovy:gradle-groovy-android-plugin:0.3.10'
}
}
apply plugin: 'android'
apply plugin: 'groovyx.grooid.groovy-android'
android {
compileSdkVersion 'Google Inc.:Google APIs:23'
buildToolsVersion '23.0.2'
defaultConfig {
minSdkVersion 15
targetSdkVersion 23
}
buildTypes {
release {
minifyEnabled false
proguardFile getDefaultProguardFile('proguard-android.txt')
}
}
}
repositories {
jcenter()
}
project.androidGroovy {
options {
sourceCompatibility = '1.7'
targetCompatibility = '1.7'
}
}
dependencies {
compile 'org.codehaus.groovy:groovy:2.4.6:grooid'
compile 'com.arasthel:swissknife:1.4.0'
compile 'com.google.android.gms:play-services-drive:8.4.0'
}
This is the GoogleApiGroovyTest.groovy
package com.loloof64.android.google_api_test
import android.app.Activity
import android.os.Bundle
import android.content.IntentSender
import android.widget.Toast
import android.content.Context
import android.util.Log
import groovy.transform.CompileStatic
import com.arasthel.swissknife.dsl.components.GAsyncTask
import com.google.android.gms.common.api.GoogleApiClient
import com.google.android.gms.common.api.GoogleApiClient.Builder
import com.google.android.gms.drive.Drive
import com.google.android.gms.common.ConnectionResult
import com.google.android.gms.common.GooglePlayServicesUtil
import com.google.android.gms.common.api.GoogleApiClient.ConnectionCallbacks
import com.google.android.gms.common.api.GoogleApiClient.OnConnectionFailedListener
import com.google.android.gms.drive.DriveFolder
import com.google.android.gms.drive.DriveApi
import com.google.android.gms.common.api.PendingResult
@CompileStatic
public class GoogleApiGroovyTest extends Activity
implements GoogleApiClient.ConnectionCallbacks, GoogleApiClient.OnConnectionFailedListener
{
private GoogleApiClient googleApiClient
private final static int RESOLVE_CONNECTION_REQUEST_CODE = 4
private final static String APP_LOGGER_REF = "GoogleApiGroovyTest"
@Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState)
setContentView(R.layout.main)
googleApiClient = new GoogleApiClient.Builder(this).addApi(Drive.API).addScope(Drive.SCOPE_APPFOLDER).addConnectionCallbacks(this).addOnConnectionFailedListener(this).build()
googleApiClient.connect()
}
@Override
public void onConnected(Bundle connectionHint){
Toast.makeText(this, "Connected to Google Drive", Toast.LENGTH_SHORT).show()
Context myThis = this
async { context, GAsyncTask task ->
task.after {
Toast.makeText(myThis, "Finally printed items into screen", Toast.LENGTH_SHORT).show()
}
task.error { err ->
Toast.makeText(this, "Error updating list files !", Toast.LENGTH_SHORT).show()
Log.e(APP_LOGGER_REF, err.message)
err.stackTrace.each { element ->
Log.e(APP_LOGGER_REF, element.toString())
}
}
loadExplorerItems()
true // Seem as returning a value is needed for the async task code to be executed
}
}
@Override
public void onConnectionSuspended(int cause) {
//TODO
}
@Override
public void onConnectionFailed(ConnectionResult connectionResult) {
// This block section is mandatory for GoogleApiClient to recover connection failure
if (connectionResult.hasResolution()) {
try {
connectionResult.startResolutionForResult(this, RESOLVE_CONNECTION_REQUEST_CODE)
} catch (IntentSender.SendIntentException e) {
// Unable to resolve
Toast.makeText(this, "Failed to connect to Google account !", Toast.LENGTH_SHORT).show()
}
} else {
GooglePlayServicesUtil.getErrorDialog(connectionResult.getErrorCode(), this, 0).show()
}
// End of block section
}
private void loadExplorerItems(){
Context myThis = this
DriveFolder appFolder = DriveApi.getAppFolder(googleApiClient)
PendingResult<DriveApi.MetadataBufferResult> pendingChildren = appFolder.listChildren(googleApiClient)
pendingChildren.setResultCallback {DriveApi.MetadataBufferResult result -> processResult:{
if (result.getStatus().isSuccess()){
Toast.makeText(myThis, "Retrieved root content", Toast.LENGTH_SHORT).show()
}
else {
Toast.makeText(myThis, "Failed to get root content", Toast.LENGTH_SHORT).show()
}
}}
}
}
This is the error stacktrace :
04-08 16:58:53.549 3261 3261 E GoogleApiGroovyTest: Cannot cast object 'interface com.google.android.gms.drive.DriveApi' with class 'java.lang.Class' to class 'com.google.android.gms.drive.DriveApi'
04-08 16:58:53.575 3261 3261 E GoogleApiGroovyTest: org.codehaus.groovy.runtime.typehandling.DefaultTypeTransformation.continueCastOnSAM(DefaultTypeTransformation.java:405)
04-08 16:58:53.575 3261 3261 E GoogleApiGroovyTest: org.codehaus.groovy.runtime.typehandling.DefaultTypeTransformation.continueCastOnNumber(DefaultTypeTransformation.java:319)
04-08 16:58:53.575 3261 3261 E GoogleApiGroovyTest: org.codehaus.groovy.runtime.typehandling.DefaultTypeTransformation.castToType(DefaultTypeTransformation.java:232)
04-08 16:58:53.575 3261 3261 E GoogleApiGroovyTest: org.codehaus.groovy.runtime.ScriptBytecodeAdapter.castToType(ScriptBytecodeAdapter.java:603)
04-08 16:58:53.575 3261 3261 E GoogleApiGroovyTest: com.loloof64.android.google_api_test.GoogleApiGroovyTest.loadExplorerItems(GoogleApiGroovyTest.groovy:91)
04-08 16:58:53.575 3261 3261 E GoogleApiGroovyTest: com.loloof64.android.google_api_test.GoogleApiGroovyTest.access$0(GoogleApiGroovyTest.groovy)
04-08 16:58:53.576 3261 3261 E GoogleApiGroovyTest: com.loloof64.android.google_api_test.GoogleApiGroovyTest$_onConnected_closure1.doCall(GoogleApiGroovyTest.groovy:62)
04-08 16:58:53.576 3261 3261 E GoogleApiGroovyTest: java.lang.reflect.Method.invoke(Native Method)
04-08 16:58:53.576 3261 3261 E GoogleApiGroovyTest: org.codehaus.groovy.reflection.CachedMethod.invoke(CachedMethod.java:93)
04-08 16:58:53.576 3261 3261 E GoogleApiGroovyTest: groovy.lang.MetaMethod.doMethodInvoke(MetaMethod.java:325)
04-08 16:58:53.576 3261 3261 E GoogleApiGroovyTest: org.codehaus.groovy.runtime.metaclass.ClosureMetaClass.invokeMethod(ClosureMetaClass.java:294)
04-08 16:58:53.576 3261 3261 E GoogleApiGroovyTest: groovy.lang.MetaClassImpl.invokeMethod(MetaClassImpl.java:1021)
04-08 16:58:53.576 3261 3261 E GoogleApiGroovyTest: groovy.lang.Closure.call(Closure.java:426)
04-08 16:58:53.576 3261 3261 E GoogleApiGroovyTest: com.arasthel.swissknife.dsl.components.GAsyncTask.doInBackground(GAsyncTask.groovy:49)
04-08 16:58:53.576 3261 3261 E GoogleApiGroovyTest: android.os.AsyncTask$2.call(AsyncTask.java:295)
04-08 16:58:53.576 3261 3261 E GoogleApiGroovyTest: java.util.concurrent.FutureTask.run(FutureTask.java:237)
04-08 16:58:53.576 3261 3261 E GoogleApiGroovyTest: android.os.AsyncTask$SerialExecutor$1.run(AsyncTask.java:234)
04-08 16:58:53.576 3261 3261 E GoogleApiGroovyTest: java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1113)
04-08 16:58:53.576 3261 3261 E GoogleApiGroovyTest: java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:588)
04-08 16:58:53.576 3261 3261 E GoogleApiGroovyTest: java.lang.Thread.run(Thread.java:818)
Meanwhile, the DriveApi.getAppFolder method has the following signature :
abstract DriveFolder getAppFolder(GoogleApiClient apiClient)
and neither the DriveApi class, not the DriveFolder class take class parameter. So I can't understand the really meaning of the Stacktrace error.
Hmmm, I don't understand where that error is coming from either, but the fact that you're trying to call a method on an interface as if you were calling a static method on a class, may have something to do with it:
DriveFolder appFolder = DriveApi.getAppFolder(googleApiClient)
DriveApi
is an interface, so it doesn't have any method implementations. And, getAppFolder()
is an instance method, not a static method. So what you need is an implementation of DriveApi
, which you can get from Drive
:
DriveFolder appFolder = Drive.DriveApi.getAppFolder(googleApiClient)