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.
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?
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).
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.
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.
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;
}
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.
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.
Related
I'm using 'com.github.javiersantos:PiracyChecker:1.2.3' because my app is not yet integrates AndroidX.
I have numerous reports from user reviews in my app's Google Play page that they have installed the app from the Google Play Store, yet they getting the piracy warning message.
Here are some examples:
Also got a user report via email:
My app have 4k reviews and only 3 of them are like this, but I don't know the exact user count because there could be users who don't comment about this issue.
What is going on?
I use it like this:
public static void showPiracyActivityIfNeeded(final Activity activity) {
if (!BuildConfig.DEBUG) {
//Releaseb build, piracy check.
new PiracyChecker(activity)
.enableInstallerId(InstallerID.GOOGLE_PLAY)
.callback(new PiracyCheckerCallback() {
#Override
public void allow() {
}
#Override
public void dontAllow(#NonNull PiracyCheckerError piracyCheckerError, #Nullable PirateApp pirateApp) {
Intent intent = new Intent(activity, PiracyWarningActivity.class);
activity.startActivity(intent);
activity.finish();
}
})
.start();
}
}
Thanks in advance.
It seems that your Google Play Services are unavailable. Try to check it before start your PiracyActivity:
const val PLAY_SERVICES_RESOLUTION_REQUEST = 9000
fun AppCompatActivity.checkPlayServices(): Boolean {
val apiAvailability = GoogleApiAvailability.getInstance()
val resultCode = apiAvailability.isGooglePlayServicesAvailable(this)
if (resultCode != ConnectionResult.SUCCESS) {
if (apiAvailability.isUserResolvableError(resultCode)) {
apiAvailability.getErrorDialog(this, resultCode, PLAY_SERVICES_RESOLUTION_REQUEST)
.show()
}
return false
}
return true
}
And then:
public static void showPiracyActivityIfNeeded(final Activity activity) {
if (!BuildConfig.DEBUG && activity.checkPlayServices()) { ...
Also note, there are a lot of devices that has Google Play Services turned off because of various reasons, so check availability of Services every time you need it.
I am new to Android programming world.
I was trying to create a G+ login using documentation at https://developers.google.com/+/mobile/android/samples/quickstart-android.
(I did that using android studio)
I am successfully able to log in and log out on my Moto-G (Android version 5.0.2). However, I'm unable to do the same with Samsung Galaxy Trend (Android version 4.1.2). The error that I'm getting here is: "Google Play services is not available. This application will close."
I have not done anything apart from what is mentioned in the documentation.
Can somebody please guide me on what is going wrong here?
Thanks!
It happens me when my android was not updated here is the code that check, i used 2 years ago
**
* Verify that Google Play services is available before making a request.
*
* #return true if Google Play services is available, otherwise false
*/
private boolean servicesConnected() {
// Check that Google Play services is available
int resultCode =
GooglePlayServicesUtil.isGooglePlayServicesAvailable(getActivity());
// If Google Play services is available
if (ConnectionResult.SUCCESS == resultCode) {
// In debug mode, log the status
//Log.d(LocationUtils.APPTAG, getString(R.string.play_services_available));
// Continue
return true;
// Google Play services was not available for some reason
} else {
// Display an error dialog
Dialog dialog = GooglePlayServicesUtil.getErrorDialog(resultCode, getActivity(), 0);
if (dialog != null) {
ErrorDialogFragment errorFragment = new ErrorDialogFragment();
errorFragment.setDialog(dialog);
errorFragment.show(getFragmentManager(), "Baja Wanted");
}
return false;
}
}
/**
* Show a dialog returned by Google Play services for the
* connection error code
*
* #param errorCode An error code returned from onConnectionFailed
*/
private void showErrorDialog(int errorCode) {
// Get the error dialog from Google Play services
Dialog errorDialog = GooglePlayServicesUtil.getErrorDialog(
errorCode,
getActivity(),
CONNECTION_FAILURE_RESOLUTION_REQUEST);
// If Google Play services can provide an error dialog
if (errorDialog != null) {
// Create a new DialogFragment in which to show the error dialog
ErrorDialogFragment errorFragment = new ErrorDialogFragment();
// Set the dialog in the DialogFragment
errorFragment.setDialog(errorDialog);
// Show the error dialog in the DialogFragment
errorFragment.show(getFragmentManager(), "Baja Wanted");
}
}
}
/**
* Define a DialogFragment to display the error dialog generated in
* showErrorDialog.
*/
public static class ErrorDialogFragment extends DialogFragment {
// Global field to contain the error dialog
private Dialog mDialog;
/**
* Default constructor. Sets the dialog field to null
*/
public ErrorDialogFragment() {
super();
mDialog = null;
}
/**
* Set the dialog to display
*
* #param dialog An error dialog
*/
public void setDialog(Dialog dialog) {
mDialog = dialog;
}
/*
* This method must return a Dialog to the DialogFragment.
*/
#Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
return mDialog;
}
}
}
Google Play Services util
https://developers.google.com/android/reference/com/google/android/gms/common/GooglePlayServicesUtil
I use code from this page.
First problem - I copy and paste all this code, but then I start this activity I see toast with error message (and screen dimming).
Second problem - I can't use this code:
int errorCode = GooglePlusUtil.checkGooglePlusApp(this);
if (errorCode != GooglePlusUtil.SUCCESS) {
GooglePlusUtil.getErrorDialog(errorCode, this, 0).show();
}
I see this error:
This fragment from build.gradle
dependencies {
...
compile 'com.google.android.gms:play-services:6.5.+'
...
}
P.S. I want use Google Plus for login in my app.
UPDATE1 This screenshot from SDK Manager:
/**
* #param activity activity passed from activity that calls checkPlayServices().
* #param context getting the current context from the activity .
*/
public static boolean checkPlayServices(Activity activity, Context context) {
int resultCode = GooglePlayServicesUtil.isGooglePlayServicesAvailable(context);
if (resultCode != ConnectionResult.SUCCESS) {
if (GooglePlayServicesUtil.isUserRecoverableError(resultCode)) {
GooglePlayServicesUtil.getErrorDialog(resultCode, activity,
Config.PLAY_SERVICES_RESOLUTION_REQUEST).show();
} else {
Log.i(TAG, "This device is not supported.");
activity.finish();
}
return false;
}
I'm taking a look at this example
https://developer.android.com/training/location/retrieve-current.html#CheckServices
Here is the code in question:
public class MainActivity extends FragmentActivity {
...
private boolean servicesConnected() {
...
if (ConnectionResult.SUCCESS == resultCode) {
...
// Google Play services was not available for some reason.
// resultCode holds the error code.
} else {
// Get the error dialog from Google Play services
Dialog errorDialog = GooglePlayServicesUtil.getErrorDialog(
resultCode,
this,
CONNECTION_FAILURE_RESOLUTION_REQUEST);
...
}
}
}
If we take a look at GooglePlayServicesUtil.getErrorDialog(..) we are passing a reference to this which happens to be an Activity.
The question is:
Would this cause a memory leak during a configuration change?
I guess the answer depends on how/if GooglePlayServicesUtil.getErrorDialog(..) keeps the reference to Activity internally.
Yep on my app it used to leak
If you have the Google play services error dialog up and then rotate again it will leak
This is the solution I put in place to solve the leak but this assumes your Google play services check is in onResume
public class MainActivity extends Activity
{
private Dialog googlePlayErrorDialog;
#Override
protected void onResume()
{
// TODO Auto-generated method stub
super.onResume();
int isAvaiable = GooglePlayServicesUtil.isGooglePlayServicesAvailable(this);
if(isAvaiable == ConnectionResult.SUCCESS)
{
Log.d("TEST", "GPS IS OK");
}
else if(isAvaiable == ConnectionResult.SERVICE_MISSING ||
isAvaiable == ConnectionResult.SERVICE_VERSION_UPDATE_REQUIRED ||
isAvaiable == ConnectionResult.SERVICE_DISABLED)
{
googlePlayErrorDialog = GooglePlayServicesUtil.getErrorDialog(isAvaiable, this, 10);
googlePlayErrorDialog.show();
}
}
#Override
protected void onPause()
{
// TODO Auto-generated method stub
super.onPause();
if(googlePlayErrorDialog != null)
{
googlePlayErrorDialog.dismiss();
}
}
So the deal here is that I set the getErrorDialog equal to one my own dialog variable and then in onPause do a simple null check (to avoid dreaded null pointer exception!) and call dismiss.
I got the idea from reading this if you want more information
http://publicstaticdroidmain.com/2012/01/avoiding-android-memory-leaks-part-1/
I am trying to handle use cases where the user doesn't have Play set up correctly. It seems extremely straight forward, but I can't get the dialog to do anything. I have the following code in onCreate for a FragmentActivity that uses Maps v2. I have ensured that execution does go inside the if statements.
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_map);
this.helper = (DatabaseHelper) OpenHelperManager.getHelper(this, DatabaseHelper.class);
int googlePlayStatus = GooglePlayServicesUtil.isGooglePlayServicesAvailable(this);
if(googlePlayStatus != ConnectionResult.SUCCESS) {
if(GooglePlayServicesUtil.isUserRecoverableError(googlePlayStatus)) {
GooglePlayServicesUtil.getErrorDialog(googlePlayStatus, this, googlePlayStatus).show();
}
}
//... do some stuff, such as use CameraUpdateFactory which throws NPE.
}
I have tried inserting the code into another activity, without the if checks, and the dialog shows just fine.
If a i am getting it right, you are trying to get the dialog error to be shown. Try this:
Edited:
Ok, i was having the same problem as you some time ago, so this is the exact code i use on one of my projects. I call the 'getActivity' on 'isGooglePlayServicesAvailable' instead of passing this.
int checkGooglePlayServices = GooglePlayServicesUtil.isGooglePlayServicesAvailable(getActivity());
if (checkGooglePlayServices != ConnectionResult.SUCCESS) {
Dialog dialog = GooglePlayServicesUtil.getErrorDialog(checkGooglePlayServices, getActivity(), DIALOG_GET_GOOGLE_PLAY_SERVICES);
dialog.show();
}