3

I'm checking avalibility of google play services on device. I do it with these code:

final int resultCode = GooglePlayServicesUtil.isGooglePlayServicesAvailable(this);
if (resultCode != ConnectionResult.SUCCESS) {
 final DialogInterface.OnCancelListener cancelListener = new DialogInterface.OnCancelListener() {
                @Override
                public void onCancel(final DialogInterface dialog) {
                    finish();
                }
            };
            final Dialog errorDialog = GooglePlayServicesUtil.getErrorDialog(
                    resultCode, this, GOOGLE_PLAY_SERVICES_REQUEST_CODE, cancelListener
            );
            errorDialog.show();
}

I get resultCode = 2 (it's mean that Google Play Services needs to update). Dialog is shown, but instead of text, I get paths to layout.

enter image description here

It's looks like there are some interference of resource in app and resource in PlaYServices lib. But how it's possible and how to avoid id?

Alexander Mikhaylov
  • 1,790
  • 1
  • 13
  • 23
  • Are those layout paths existing in your main project or library projects? – HHK Jul 01 '14 at 16:58
  • It would seem that resource ids were incorrectly generated for this app. Obviously the dialog intended to show strings in those places, and doing something like `getResources().getString(R.layout.my_layout)` will return the string `res/layout/my_layout.xml`. (1) Have you already tried the regular solutions, like cleaning / rebuilding the project and its libraries? (2) Are you assembling this app in some kind of non-standard way? – matiash Jul 01 '14 at 23:38
  • Just to make myself clear, I'm not claiming that Google Play Services incorrectly uses `R.layout.dialog_share` instead of `R.string.something`. :) Rather, _the int values those fields of the `R` class are mapped to are probably incorrect_, and don't match the right values in the binary resources of the apk. Hence my questions 1 and 2 in the above comment. – matiash Jul 02 '14 at 00:29
  • Yes, I thought so. But I've tried to print ids (int values) for R.layout.dialog_share and string id from google play services and they are different. So it' doesn't looks like problem in id generation. And yes, I've tried to clean project and libs. – Alexander Mikhaylov Jul 02 '14 at 06:22
  • are you using the latest version of google play services lib?? – LordRaydenMK Jul 02 '14 at 07:04
  • @LordRaydenMK I'm using versiong 4452000 of google play services lib. It's google play v 4.4. It's not the latest, but 5.0 has not installed to most of devices yes – Alexander Mikhaylov Jul 02 '14 at 10:23
  • As I have said already if this is an incompatability between two versions of Google Play Services then it is a Google bug. You could file a report but you are wasting your time, because they will not fix errors on old versions. Your best way forward is to work around it by putting the message out via toast or whatever. – IanB Jul 03 '14 at 16:07
  • @IanB ok, thank you. I think I will use some workaround. I thought someone faced this problem and can say why it's happened. – Alexander Mikhaylov Jul 03 '14 at 17:55
  • You are welcome. Although I have not seen this explicitly described as a "Google bug", this is clearly implied both in the code that people are writing (eg several solutions use toasts in particular scenarios) and the way people are describing the problem (eg better to update GPS manually). It seems very likely to me that Google did not test all possible upgrade paths. I stand by my position in my answer below. If this error is being described as " recoverable" then this is a Google bug and so far nobody has come up with a more likely explanation. – IanB Jul 03 '14 at 19:24
  • @IanB I highly doubt Google is to blame here. These strings are NOT part of the Google Play Services _app_. Rather, they are in the resources for the Google Play Services _Library_, which is included inside this app. So I would suspect that the app itself is being, somehow, incorrectly built. -- @Demand: you are including Google Play Services in the standard way, i.e. as a library project, instead of just copying the jar, right? Maybe you could inspect, using reflection, the ids in the `com.google.android.gms.R.string` class, to see if they collide with your R class? That could provide clues. – matiash Jul 04 '14 at 06:56
  • Matiash, the strings are part of the library, and they are accessed via the library and it is the library that is changing and most likely the cause of the problem. The probability that this is some sort of spurious build problem is basically zero. Nobody else has reported anything similiar, but there are reports of problems in the library (including the ones I have referred to in my answer). The code that accesses these strings varies from one version of the library to another. In a production scenario, the old app will not have been recompiled so build issues are irrelevant. – IanB Jul 04 '14 at 08:21
  • @IanB Well, I respectfully disagree. – matiash Jul 04 '14 at 16:48
  • No problem. We can agree to differ, but I and hundreds of others have got this working with Eclipse, so the accepted "answer" is a poor one. I will probably frame this question in a better way in the forseeable future (as a new question), and post a proper solution to it. – IanB Jul 04 '14 at 17:13
  • @IanB While the answer is poor, I believe it is correct. The fact that many others (myself included too) have this working would tend to support precisely the theory that it was a build issue with _this_ project, not the other way around! :) – matiash Jul 04 '14 at 19:12
  • I'll respectfully agree to disagree with you ! – IanB Jul 04 '14 at 20:17
  • @IanB And I agree to agree to disagree. We can go on with this, if you like! ;) – matiash Jul 06 '14 at 19:55

6 Answers6

2

Since the accepted answer is somewhat unclear, I'll leave a signpost with my conclusions (mostly extracted from the comments on the question) which I believe are correct.

Short version: It seems that resource ids were incorrectly generated for this app.

It's obvious that the Google Play Services dialog intended to show strings in those places. The getErrorDialog() method is implemented like this (obfuscated, but the meaning can still be understood):

...
case 1: 
    return localBuilder.setTitle(R.string.common_google_play_services_install_title).create();
case 3: 
    return localBuilder.setTitle(R.string.common_google_play_services_enable_title).create();
case 2: 
   return localBuilder.setTitle(R.string.common_google_play_services_update_title).create();
...

Also, mistakenly doing something like getResources().getString(R.layout.my_layout) will return a string with the name of the original resource file ("res/layout/my_layout.xml").

So, we can conclude that, for some reason, the value of the Play Services Library resource, say, com.google.android.gms.R.string.common_google_play_services_install_title is actually the same as for the resource R.layout.dialog_share in the application project.

This probably stems for an incorrect build process, or an incorrect usage of the Google Play Services library (for example, including its jar directly, without the corresponding library process).

matiash
  • 54,791
  • 16
  • 125
  • 154
1

I have tested the code with google play service library version 4452000(use version >= 4452000). The code is as follows:

public class MainActivity extends Activity{
    ProgressBar pBar;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
       final int resultCode = GooglePlayServicesUtil.isGooglePlayServicesAvailable(this);
       if (resultCode != ConnectionResult.SUCCESS) {
       final DialogInterface.OnCancelListener cancelListener = new DialogInterface.OnCancelListener() {
                    @Override
                    public void onCancel(final DialogInterface dialog) {
                        finish();
                    }
                };
                final Dialog errorDialog = GooglePlayServicesUtil.getErrorDialog(
                        resultCode, this, 10, cancelListener
                );
                errorDialog.show();
        }
    } 
}

Check your version of google play services and update if needed.

Aashutosh Sharma
  • 1,483
  • 2
  • 17
  • 29
1

Here's the class I've been working on to check google play. It's not in production later this summer it will be so let me know with a comment if you have problems. It works tested on zten9120 and HTC EVO. The flow is like this. If static method isGooglePlay(context) returns false. Initialize the class and call the non static isgoogleplay() which will present the dialog to the user if googleplay services is not installed. The oncofigurationchange method handles when the device is rotated. onstop sets the class to null.

Modify three events in your activity.

@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    if (!MyGooglePlay.isGooglePlay(getApplicationContext())) {
        myGP = new MyGooglePlay(this);
        myGP.isGooglePlay();
    }


@Override
public void onStop() {
    super.onStop();
    myGP = null;
}


@Override
public void onConfigurationChanged(Configuration newConfig) {
    super.onConfigurationChanged(newConfig);
    if (myGP != null) {
        if (myGP.errorFragment.isVisible()) {
            myGP.errorFragment.dismissAllowingStateLoss();
        }
    }
}

Here's the code which I keep in separate class

package com.gosylvester.bestrides.util;

import android.app.Dialog;

import android.content.Context;
import android.content.IntentSender;

import android.os.Bundle;
import android.support.v4.app.DialogFragment;

import android.support.v4.app.FragmentManager;
import android.support.v7.app.ActionBarActivity;

import com.google.android.gms.common.ConnectionResult;
import com.google.android.gms.common.GooglePlayServicesUtil;

public class MyGooglePlay {

    private static final int CONNECTION_FAILURE_RESOLUTION_REQUEST = 31502;
    private ActionBarActivity activity;
    private FragmentManager fragManager;

    public MyGooglePlay(ActionBarActivity activity) {
        this.activity = activity;
        this.fragManager = activity.getSupportFragmentManager();
    }

    public static boolean isGooglePlay(Context context) {
        return (GooglePlayServicesUtil.isGooglePlayServicesAvailable(context) == ConnectionResult.SUCCESS);
    }

    public boolean isGooglePlay() {
        if (isGooglePlay(activity)) {
            return true;
        } else {
            return checkGooglePlay();
        }
    }

    private static final String DIALOG_ERROR = "dialog_error";

    public ErrorDialogFragment errorFragment;

    private boolean checkGooglePlay() {
        int mIsGooglePlayServicesAvailable = GooglePlayServicesUtil
                .isGooglePlayServicesAvailable(activity);

        switch (mIsGooglePlayServicesAvailable) {
        case ConnectionResult.SUCCESS:
            return true;
        default:

            Dialog errorDialog = GooglePlayServicesUtil.getErrorDialog(
                    mIsGooglePlayServicesAvailable, activity,
                    CONNECTION_FAILURE_RESOLUTION_REQUEST);
            // If Google Play services can provide an error dialog
            if (errorDialog != null) {
                // Create a new DialogFragment for the error dialog
                errorFragment = ErrorDialogFragment.newInstance();
                // Set the dialog in the DialogFragment
                errorFragment.setDialog(errorDialog);

                // Show the error dialog in the DialogFragment
                errorFragment.show(fragManager, "LocationUpdates");
            }
            // case ConnectionResult.SERVICE_MISSING:
            // case ConnectionResult.SERVICE_VERSION_UPDATE_REQUIRED:
            // case ConnectionResult.SERVICE_DISABLED:
            // case ConnectionResult.SERVICE_INVALID:
            // case ConnectionResult.DATE_INVALID:
        }

        return false;
    }

    public void dismissMe() {
        DialogFragment frag = (DialogFragment) fragManager
                .findFragmentByTag("LocationUpdates");
        if (frag != null) {
            frag.dismissAllowingStateLoss();
        }
    }

    public static class ErrorDialogFragment extends DialogFragment {
        // Global field to contain the error dialog
        private Dialog mDialog;




        static ErrorDialogFragment newInstance() {
            ErrorDialogFragment d = new ErrorDialogFragment();
            return d;
        }

        // Default constructor. Sets the dialog field to null
        public ErrorDialogFragment() {
            super();
            mDialog = null;
        }

        // Set the dialog to display
        public void setDialog(Dialog dialog) {
            mDialog = dialog;
        }


        public void onPause(){
            super.onPause();
            this.dismissAllowingStateLoss();
        }

        // Return a Dialog to the DialogFragment.
        @Override
        public Dialog onCreateDialog(Bundle savedInstanceState) {
            return mDialog;
        }
    }

    public void onConnectionFailed(ConnectionResult connectionResult) {
        /*
         * Google Play services can resolve some errors it detects. If the error
         * has a resolution, try sending an Intent to start a Google Play
         * services activity that can resolve error.
         */
        if (connectionResult.hasResolution()) {
            try {
                // Start an Activity that tries to resolve the error
                connectionResult.startResolutionForResult(activity,
                        CONNECTION_FAILURE_RESOLUTION_REQUEST);
                /*
                 * Thrown if Google Play services canceled the original
                 * PendingIntent
                 */
            } catch (IntentSender.SendIntentException e) {
                // Log the error
                e.printStackTrace();
            }
        } else {
            /*
             * If no resolution is available, display a dialog to the user with
             * the error.
             */
            showErrorDialog(connectionResult.getErrorCode(), activity);
        }
    }

    /* Creates a dialog for an error message */
    private void showErrorDialog(int errorCode, ActionBarActivity activity) {
        // Create a fragment for the error dialog
        ErrorDialogFragment dialogFragment = new ErrorDialogFragment();
        // Pass the error that should be displayed
        Bundle args = new Bundle();
        args.putInt(DIALOG_ERROR, errorCode);
        dialogFragment.setArguments(args);
        dialogFragment
                .show(activity.getSupportFragmentManager(), "errordialog");
    }

}

Good Luck with getting google play services installed.

danny117
  • 5,581
  • 1
  • 26
  • 35
-2
  public static boolean isGooglePlayServiceAvailable(Context context) {
    boolean isAvailable = false;
    int result = GooglePlayServicesUtil
            .isGooglePlayServicesAvailable(context);
    if (result == ConnectionResult.SUCCESS) {
        Log.d(TAG, "Play Service Available");
        isAvailable = true;
    } else {
        Log.d(TAG, "Play Service Not Available");
        if (GooglePlayServicesUtil.isUserRecoverableError(result)) {
            GooglePlayServicesUtil.getErrorDialog(result,
                    (Activity) context, PLAY_SERVICES_RESOLUTION_REQUEST)
                    .show();
        } else {
            Log.d(TAG, "Play Service Not Available");
            GooglePlayServicesUtil.getErrorDialog(result,
                    (Activity) context, PLAY_SERVICES_RESOLUTION_REQUEST)
                    .show();
        }
    }
    return isAvailable;
} 
user2851150
  • 397
  • 5
  • 12
  • Ok, that's the difference with my code? I call getErrorDialog with exact the same params. I remove part of my code with checking isUserRecoverable, because it's not related to problem. – Alexander Mikhaylov Jun 27 '14 at 10:53
-2

Updated answer : (as per GooglePlayServicesUtil.getErrorDialog is null)

If Google Play Services is not installed on the device, you may not be able to use the error dialog.

As per Rahim's comment in the above, you should only use the dialog if you have an "isUserRecoverableError" (his code):

int status = GooglePlayServicesUtil.isGooglePlayServicesAvailable(this);
if (status != ConnectionResult.SUCCESS) {
    if (GooglePlayServicesUtil.isUserRecoverableError(status)) {
    GooglePlayServicesUtil.getErrorDialog(status, this, 
    REQUEST_CODE_RECOVER_PLAY_SERVICES).show();
    } else {
      Toast.makeText(this, "This device is not supported.", Toast.LENGTH_LONG).show();
      finish();
    }
}

UPDATE - (from http://www.riskcompletefailure.com/2013/03/common-problems-with-google-sign-in-on.html)

One additional bug that surfaced quite a lot around the release of the latest version of Google Play Services was the onConnectionFailed method being called with a ConnectionResult which does not have a resolution, and has an error code of ConnectionResult.SERVICE_VERSION_UPDATE_REQUIRED.

As you might guess from the name, this indicates that the version of Google Play Services on the device is too low. Normally new versions will be updated automatically, but there is always a time delay in the roll out, so it is quite possible to get this error as updates are released.

You can handle this in the onConnectionFailed by calling getErrorDialog on GooglePlayServicesUtil, but the best way is to actually check whether Google Play Services is installed and up to date before even trying to connect. You can see a snippet of how to do this in the documentation.

So this is suggesting that this error (as you yourself say) should be recoverable, although note the clause that I have made bold. I am not convinced that this dialog would always be usable. Common sense suggests to me that this might depend on the version from which you were upgrading. So I recommend that you explicitly check that the error is marked as recoverable. If it is marked as recoverable then this looks like a bug in Google Play Services.

Community
  • 1
  • 1
IanB
  • 3,489
  • 1
  • 20
  • 24
  • I'm using Error dialog which provided by GooglePlayServices lib. GooglePlayServicesUtil.getErrorDialog() is standard way to show error is coming from GooglePlayServices. If I will decorate this wrong dialog with DialogFragment, I think it will not help. But I will try. – Alexander Mikhaylov Jun 30 '14 at 10:15
  • GooglePlayServicesUtil.getErrorDialog() not null in my case. It's null only when resultCode == ConnectionResult.SUCCESS. If resultCode not quals to SUCCESS, then getErrorDialog not null. But dialog is drawing like on my picture. It's happened when GooglePlayServices needs to update. – Alexander Mikhaylov Jun 30 '14 at 11:15
  • 1
    because your solution will not work for me. My google play services availibility status equals to SERVICE_VERSION_UPDATE_REQUIRED. So this is recoverable and getErrorDialog() returns dialog (not null). So when I show this dialog, i see the picture I've posted. It's not about dialog not created, it's about dialog with strange text created by GooglePlayServicesLib – Alexander Mikhaylov Jun 30 '14 at 12:42
  • Please review my amended answer. – IanB Jun 30 '14 at 13:08
  • Are you assuming that this error will be "recoverable" or have you PROVEN in your code that IN YOUR SPECIFIC CASE the error is described as recoverable. That (as Hamlet said) is the question. – IanB Jul 03 '14 at 19:35
-4

I found solution. I don't undertand why it's happening, but there is a solution.

I've built my project with maven and include a google play services framework as android library project.

Today, I've migrated to gradle and include dependecy go GPS with gradle and it solved my problem.

Alexander Mikhaylov
  • 1,790
  • 1
  • 13
  • 23