With Google Play Services' Activity Recognition, they recommend that if the service disconnects (which it might) then we should remove the client:
http://developer.android.com/training/location/activity-recognition.html
In some cases, Location Services may disconnect from the activity
recognition client before you call disconnect(). To handle this
situation, implement onDisconnected(). In this method, set the request
flag to indicate that a request is not in progress, and delete the
client
That's fine, but it gives no instructions for how to reconnect [safely]. I'm running this from a foreground service which needs to maintain activity recognition at all times, so following disconnection:
#Override
public void onDisconnected() {
mRecognitionEnabled = false;
mRequestInProgress = false;
mRecognitionClient = null;
//Re-initialise Activity Recognition if service is still running
if (sServiceRunning) {
triggerActivityRecognition();
}
}
I reinstantiate the client and reconnect:
private void triggerActivityRecognition() {
if (!mRequestInProgress ) {
mRequestInProgress = true;
mRecognitionClient = new ActivityRecognitionClient(this, this, this);
mRecognitionClient.connect();
}
}
But according to some of the bug reports I'm getting, there's an exception occurring as follows:
java.lang.NullPointerException
at com.google.android.gms.internal.bh.a(Unknown Source)
at com.google.android.gms.internal.k.f(Unknown Source)
at com.google.android.gms.internal.k$e.onServiceConnected(Unknown Source)
at com.google.android.gms.internal.l.a(Unknown Source)
at com.google.android.gms.internal.k.connect(Unknown Source)
at com.google.android.gms.location.ActivityRecognitionClient.connect(Unknown Source)
at com.myapp.MyService.triggerActivityRecognition(MyService.java:316)
at com.myapp.MyService.onDisconnected(MyService.java:407)
at com.google.android.gms.internal.k.A(Unknown Source)
at com.google.android.gms.internal.k$e.onServiceDisconnected(Unknown Source)
at com.google.android.gms.internal.l$a$a.onServiceDisconnected(Unknown Source)
The disconnection occurs rarely but results in the same stack trace every time.
So if this is being caused by Google Play Services, is there anything I can do to prevent it or is it a bug I need to log with Android?
This is what works for me:
Don't attempt the reconnect with the onDisconnect(), instead do nothing in the onDisconnect()
public void onDisconnected() {
//do nothing here
}
Simply use the client as before, but check if is connected
if (!mRecognitionClient.isConnected()) {
// Client is disconnected, reconnect now
mRecognitionClient.connect();
}
The PlayServices seems to reconnect very nicely.
Related
I'm implementing Google Smart Lock into an app, and I was having no trouble with the Api Client building before. In fact, I was finalizing some syntax changes and cleaning up the code (didn't even touch the code that initializes the Api Client), and my app now dies when build() is called on the Api Client builder, due to abstract method zza. Here is the error being displayed:
java.lang.AbstractMethodError: abstract method "com.google.android.gms.common.api.Api$zze com.google.android.gms.common.api.Api$zza.zza(android.content.Context, android.os.Looper, com.google.android.gms.common.internal.zzq, java.lang.Object, com.google.android.gms.common.api.GoogleApiClient$ConnectionCallbacks, com.google.android.gms.common.api.GoogleApiClient$OnConnectionFailedListener)"
at com.google.android.gms.common.api.GoogleApiClient$Builder.build(Unknown Source)
I have no clue why it suddenly started failing, and I couldn't find any changes I made that would have caused this error. Why isn't that abstract method being overridden? It's nested deep inside the library so I don't understand how I could have affected it.
I wrapped the Google Api Client calls in a manager I named CredentialManager. Here is the code I used to initialize the client:
public CredentialManager(ContextProvider contextProvider) {
mContextProvider = contextProvider;
mCredentialsApiClient = new GoogleApiClient.Builder(mContextProvider.getContext())
.addConnectionCallbacks(new GoogleApiClient.ConnectionCallbacks() {
#Override
public void onConnected(#Nullable Bundle bundle) {
Log.i(CredentialManager.TAG, "Api connected");
}
#Override
public void onConnectionSuspended(int i) {
Log.i(CredentialManager.TAG, "Connection suspended with status " + i);
}
})
.enableAutoManage(mContextProvider.getContext(), connectionFailedResult -> {
if (connectionFailedResult.hasResolution()) {
try {
connectionFailedResult.startResolutionForResult(
mContextProvider.getContext(),
CredentialManager.Codes.RESOLVE_CONNECTION_REQUEST_CODE);
} catch (IntentSender.SendIntentException e) {
// Unable to resolve, log error
Log.e(CredentialManager.TAG, "Resolution failed: " + e.getMessage());
}
} else {
//instead of displaying a dialog, just let the user continue and login manually.
Log.e(CredentialManager.TAG, "Connection failed: " + connectionFailedResult.getErrorMessage());
}
})
.addApi(Auth.CREDENTIALS_API)
.build();
}
If you have any insight as to what is causing this error, please let me know. I've scoured the internet for anyone that has seen something like this before, but couldn't find anything.
The issue was that some google play services dependencies had their versions updated and not the play-services-auth dependency used for google smart lock. The apk would compile fine, but crash when the Google Api Client was trying to initialize. The fix was to make all the versions the same, and invalidate cache + restart android studio, recompile, and run.
I have recently introduced Google TagManager into my Android app in order to push changes to app config without needing to redeploy the app.
But I am getting instances of:
java.lang.IllegalStateException: Results have already been set
at com.google.android.gms.common.internal.p.a(Unknown Source)
at com.google.android.gms.common.api.b$a.a(Unknown Source)
at com.google.android.gms.tagmanager.ed.a(Unknown Source)
at com.google.android.gms.tagmanager.ed.a(Unknown Source)
at com.google.android.gms.tagmanager.ed$b.a(Unknown Source)
at com.google.android.gms.tagmanager.ed$b.a(Unknown Source)
at com.google.android.gms.tagmanager.cj.c(Unknown Source)
at com.google.android.gms.tagmanager.ck.run(Unknown Source)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1112)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:587)
at java.lang.Thread.run(Thread.java:841)
They occur across a variety of devices from Android 4.4 to 5.0.1
As you can see there is no element of my app in the stacktrace, and I am really at a loss and to what I can do (other than remove TagManager) to avoid or mitigate the error.
I have found one reference to the same error message associated with GooglePlus login so I am thinking it might be to do with the Google Play Services library.
Anyone else seen it?
Any ideas?
Have raised issue with Play-Games project:
https://code.google.com/p/play-games-platform/issues/detail?id=209
This is an internal bug due to a race condition within TagManager and should be fixed in Google Play Services 6.7 (February 17, 2015).
See https://productforums.google.com/forum/?utm_medium=email&utm_source=footer#!msg/tag-manager/NOlng117_2g/w46OkQS5Gm8J
and also https://developers.google.com/analytics/devguides/collection/android/changelog
In the mean time you can work around it by:
private static class MyHandler implements Thread.UncaughtExceptionHandler {
private final Thread.UncaughtExceptionHandler defaultHandler;
MyHandler(Thread.UncaughtExceptionHandler defaultHandler) {
this.defaultHandler = defaultHandler;
}
#Override
public void uncaughtException(Thread thread, Throwable ex) {
String classpath = null;
if (ex != null && ex.getStackTrace().length > 0) {
classpath = ex.getStackTrace()[0].toString();
}
if (classpath != null &&
ex.getMessage().contains("Results have already been set") &&
classpath.contains("com.google.android.gms.tagmanager") ) {
// ignore
} else {
// run your default handler
defaultHandler.uncaughtException(thread, ex);
}
}
};
// Application#onCreate
public void onCreate() {
// for catching app global unhandled exceptions
final Thread.UncaughtExceptionHandler defaultHandler = Thread.getDefaultUncaughtExceptionHandler();
Thread.setDefaultUncaughtExceptionHandler(new MyHandler(defaultHandler));
}
According to this link, Google has fixed this issue in newer versions:
https://developers.google.com/analytics/devguides/collection/android/changelog
I'm getting exception reports of DeadObjectException from some devices when requesting prices for in app purchases. The exception occurs when I call getSkuDetails on my billing service connection.
I don't find the documentation on this particularly clear.
The object you are calling has died, because its hosting process no longer exists.
Am I understanding this correctly if I assume that the billing service has been killed by Android for some reason?
Why?
Is there a way to stop this from happening?
Should I stop this from happening?
How should I deal with the exception?
Is there a way I can reproduce this scenario for testing?
I have two methods
void bindToBillingService() {
AndroidLauncher.getActivity().bindService(new Intent("com.android.vending.billing.InAppBillingService.BIND"),
mServiceConn, Context.BIND_AUTO_CREATE);
}
public void unbindBillingService() {
if (getBillingServiceConnection() != null) {
AndroidLauncher.getActivity().unbindService(mServiceConn);
}
}
Should I be doing something like this?
try {
// Do something billing related
} catch (DeadObjectException e) {
unbindBillingService();
bindToBillingService();
// Wait for a connection and then try again
}
I have a custom Chromecast receiver that I launch from an Android app when the user selects their Chromecast device from the Cast button. I find that I often get a timeout on the initial connection, but the second time it works fine. Is the issue most likely my web server not responding fast enough, or are there other factors that might cause the timeout?
I'm getting the CastStatusCodes.TIMEOUT in onApplicationConnectionFailed().
My code to launch
(EDITED to include launchApplication)
Builder builder = new GoogleApiClient.Builder(mContext);
builder.addApi(Cast.API, apiOptionsBuilder.build());
builder.addConnectionCallbacks(this);
builder.addOnConnectionFailedListener(this);
mApiClient = builder.build();
if (mApiClient == null) return;
mApiClient.connect();
...
Cast.CastApi.launchApplication(mApiClient, mApplicationId)
.setResultCallback(new ResultCallback<Cast.ApplicationConnectionResult>() {
#Override
public void onResult(ApplicationConnectionResult result) {
if (result.getStatus().isSuccess()) {
onApplicationConnected(
result.getApplicationMetadata(),
result.getApplicationStatus(),
result.getSessionId(),
result.getWasLaunched());
} else {
onApplicationConnectionFailed(result.getStatus().getStatusCode());
}
}
});
The code you have posted is prior to loading the application so if you are getting a timeout in your onApplicationConnectionFailed, then it is further down in your code and not the part that you have posted here. If it is the loading of your application that fails, you need to check on your network and web server, etc.
I'm developing an Android application that casts content to Chromecast.
Sometimes in my com.google.android.gms.common.api.GoogleApiClient.ConnectionCallbacks implementation in the onConnected method, I get a
java.lang.IllegalStateException: GoogleApiClient is not connected yet.
exception.
Here is the stack trace:
FATAL EXCEPTION: main
Process: com.joaomgcd.autocast, PID: 13771
java.lang.IllegalStateException: GoogleApiClient is not connected yet.
at com.google.android.gms.internal.eg.a(Unknown Source)
at com.google.android.gms.common.api.GoogleApiClient.b(Unknown Source)
at com.google.android.gms.cast.Cast$CastApi$a.launchApplication(Unknown Source)
at com.joaomgcd.autocast.media.MediaConnectionCallbacks.onConnected(MediaConnectionCallbacks.java:37)
at com.google.android.gms.internal.dx.b(Unknown Source)
at com.google.android.gms.common.api.GoogleApiClient.bn(Unknown Source)
at com.google.android.gms.common.api.GoogleApiClient.f(Unknown Source)
at com.google.android.gms.common.api.GoogleApiClient$2.onConnected(Unknown Source)
at com.google.android.gms.internal.dx.b(Unknown Source)
at com.google.android.gms.internal.dx.bT(Unknown Source)
at com.google.android.gms.internal.dw$h.b(Unknown Source)
at com.google.android.gms.internal.dw$h.b(Unknown Source)
at com.google.android.gms.internal.dw$b.bR(Unknown Source)
at com.google.android.gms.internal.dw$a.handleMessage(Unknown Source)
at android.os.Handler.dispatchMessage(Handler.java:102)
at android.os.Looper.loop(Looper.java:136)
at android.app.ActivityThread.main(ActivityThread.java:5017)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:515)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:779)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:595)
at dalvik.system.NativeStart.main(Native Method)
This only seems to happen if I had already connected to the GoogleApiClient before and am connecting for a second time. Between the 2 calls I disconnect from the api client with the code below.
My guess is that this is a bug. Am I correct? Since I'm in the onConnected method, the GoogleApiClient should already be connected.
What can I do to get around it? Should I just wait for a while until the GoogleApiClient is really connected?
I am doing this in a service and here are the relevant bits:
when the service starts:
mMediaRouter.addCallback(mMediaRouteSelector, mediaCallback, MediaRouter.CALLBACK_FLAG_PERFORM_ACTIVE_SCAN);
mediaCallback has this code:
#Override
public void onRouteAdded(MediaRouter router, RouteInfo route) {
super.onRouteAdded(router, route);
if (route.getDescription().equals("Chromecast")) {
...
mSelectedDevice = com.google.android.gms.cast.CastDevice.getFromBundle(route.getExtras());
...
castClientListener = new CastListener(context, apiClient);
Cast.CastOptions.Builder apiOptionsBuilder = Cast.CastOptions.builder(mSelectedDevice, castClientListener);
...
apiClient.set(new GoogleApiClient.Builder(context).addApi(Cast.API, apiOptionsBuilder.build()).addConnectionCallbacks(connectionCallback).addOnConnectionFailedListener(new MediaConnectionFailedListener(context)).build());
apiClient.get().connect();
}
}
connectionCallback has this code:
#Override
public void onConnected(final Bundle arg0) {
...
Cast.CastApi.launchApplication(apiClient, UtilAutoCast.CHROMECAST_APP_ID, false).setResultCallback(connectionCallback);
...
}
The code above is the part where the crash happens.
And when I stop the service I run this code:
if (mMediaRouter != null) {
mMediaRouter.removeCallback(mediaCallback);
mMediaRouter = null;
}
if (apiClient != null) {
Cast.CastApi.stopApplication(apiClient);
if (apiClient.isConnected()) {
apiClient.disconnect();
apiClient = null;
}
}
Thanks in advance.
Google APIs for Android > GoogleApiClient
You should instantiate a client object in your Activity's onCreate(Bundle) method and then call connect() in onStart() and disconnect() in onStop(), regardless of the state.
The implementation of the GoogleApiClient appears designed for only a single instance. It's best to instantiate it only once in onCreate, then perform connections and disconnections using the single instance.
I would guess that only one GoogleApiClient can be actually be connected, but multiple instances are receiving the onConnected callback.
In your case it's probably fine to not call connect in onStart, but only in onRouteAdded.
I think this issue is very similar to Fatal Exception: java.lang.IllegalStateException GoogleApiClient is not connected yet
Have you declare following <meta> tag
<application ...>
...
<meta-data
android:name="com.google.android.gms.version"
android:value="#integer/google_play_services_version" />
...
</application>
I just forgot to write so may you also stuck with this reason.
Thank you.
From showcase app (Googlecast Github Sample CastHelloText-android ) receiver app is launched onRouteSelected (not onRouteAdded as you are doing in your code). I would try to change that. In case it does not work, I would add log lines in every method related to connection & session, and see what is happening.
Another tip: I have had crash with stopping the application (in case chromecast device is physically plugged out from power). Solution is to putCast.CastApi.stopApplication(apiClient); inside if (apiClient.isConnected()).
It seems like you are calling GoogleApiClient before it is connected
move this line in onCreate()
// First we need to check availability of play services
if (checkPlayServices()) {
// Building the GoogleApi client
//buildGoogleApiClient();
try {
mGoogleApiClient = new GoogleApiClient.Builder(this).addConnectionCallbacks(this).addOnConnectionFailedListener(this).addApi(LocationServices.API).build();
mGoogleApiClient.connect();
}catch (IllegalStateException e)
{
Log.e("IllegalStateException", e.toString());
}
createLocationRequest();
}
Hope it helps you.