I'm trying to connect mGoogleAPIClient, following this Guide.
When i debug, a little window popsup asking me what googleplus account i would like to sign in as. As soon as I select my main account and click OK, it stops from there and does absolutely nothing. No error Messages, Warnings, Infos, no nothing.
My Source:
public class MainMenu_Activity extends Activity implements GoogleApiClient.ConnectionCallbacks, GoogleApiClient.OnConnectionFailedListener {
private Button btnStart;
private Button btnSubmit;
private Button btnHOF;
private GoogleApiClient mGoogleApiClient;
public static int REQUEST_LEADERBOARD = 100;
// Request code to use when launching the resolution activity
private static final int REQUEST_RESOLVE_ERROR = 1001;
// Bool to track whether the app is already resolving an error
private boolean mResolvingError = false;
private static final String STATE_RESOLVING_ERROR = "resolving_error";
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_mainmenu);
mResolvingError = savedInstanceState != null
&& savedInstanceState.getBoolean(STATE_RESOLVING_ERROR, false);
this.mGoogleApiClient = new GoogleApiClient.Builder(this)
.addApi(Drive.API)
.addScope(Drive.SCOPE_FILE)
.addApi(Plus.API)
.addScope(Plus.SCOPE_PLUS_LOGIN)
.addScope(Plus.SCOPE_PLUS_PROFILE)
.addConnectionCallbacks(this)
.addOnConnectionFailedListener(this)
.build();
}
#Override
protected void onStart() {
super.onStart();
if (!mResolvingError) { // more about this later
mGoogleApiClient.connect();
}
}
#Override
protected void onStop() {
mGoogleApiClient.disconnect();
super.onStop();
}
#Override
public void onConnected(Bundle connectionHint) {
// Connected to Google Play services!
// The good stuff goes here.
System.out.println("CONNECTED!");
}
#Override
public void onConnectionSuspended(int cause) {
// The connection has been interrupted.
// Disable any UI components that depend on Google APIs
// until onConnected() is called.
System.out.println("SUSPENDED!");
}
#Override
public void onConnectionFailed(ConnectionResult result) {
System.out.println("Connection Failed - mResolvingError=" + mResolvingError);
if (mResolvingError) {
System.out.println("Connection Failed - Already attempting to resolve...");
// Already attempting to resolve an error.
return;
} else if (result.hasResolution()) {
System.out.println("Connection Failed - resolving now...");
try {
mResolvingError = true;
result.startResolutionForResult(this, REQUEST_RESOLVE_ERROR);
} catch (IntentSender.SendIntentException e) {
System.out.println("Connection Failed - Exception...");
// There was an error with the resolution intent. Try again.
mGoogleApiClient.connect();
}
} else {
// Show dialog using GooglePlayServicesUtil.getErrorDialog()
Dialog errDia = GooglePlayServicesUtil.getErrorDialog(result.getErrorCode(), this, 1);
errDia.show();
mResolvingError = true;
}
}
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if (requestCode == REQUEST_RESOLVE_ERROR) {
mResolvingError = false;
if (resultCode == RESULT_OK) {
// Make sure the app is not already connected or attempting to connect
if (!mGoogleApiClient.isConnecting() &&
!mGoogleApiClient.isConnected()) {
mGoogleApiClient.connect();
}
}
}
}
#Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
outState.putBoolean(STATE_RESOLVING_ERROR, mResolvingError);
}
}
As you can see, i tagged certain places to follow the procedure.
Well this is what the logcat logs:
06-02 17:52:48.175 2302-2302/com.dudewithfacial.game.gamebase I/System.out﹕
Connection Failed - mResolvingError=false 06-02 17:52:48.175
2302-2302/com.dudewithfacial.game.gamebase I/System.out﹕ Connection Failed -
resolving now...
I follow the guide step by step :(
Well appaently not really, what am i doing wrong Stackoverflow-Gurus?
Thx boys, really appreciated!
NVM, figured out i can't use Launchmode, SingleUser, SingleInstance.
Also haven't configred some of the requested APIs such as ".addApi(Plus.API)"
Problem fixed.
Related
So I am trying to connect to the Google API client, but I am not getting a response from my onConnected method or onConnectionFailed method. Both methods are like so, respectively:
public void onConnected(#Nullable Bundle bundle) {
Log.d(TAG, "OnConnected");
if (PackageManager.PERMISSION_GRANTED ==
(ContextCompat.checkSelfPermission(mParentBase, android.Manifest.permission.ACCESS_FINE_LOCATION)))
{
Log.d(TAG, "Permission Was Granted" );
mMyLocation = LocationServices.FusedLocationApi.getLastLocation(mGoogleApiClient);
if (mMyLocation == null) {
LocationServices.FusedLocationApi.requestLocationUpdates(mGoogleApiClient, requestLocation, mParentIntent);
} else {
Log.d(TAG, mMyLocation.toString());
}
} else {
ActivityCompat.requestPermissions(mParentActivity, new String[]{android.Manifest.permission.ACCESS_FINE_LOCATION}, MY_PERMISSION_ACCESS_FINE_LOCATION);
Log.d(TAG, "Permission Was Requested" );
}
}
#Override
public void onConnectionFailed(#NonNull ConnectionResult connectionResult) {
Log.i(TAG, "Connection Failed");
if (connectionResult.hasResolution()) {
try {
// Start an Activity that tries to resolve the error
connectionResult.startResolutionForResult(mParentActivity, CONNECTION_FAILURE_RESOLUTION_REQUEST);
} catch (IntentSender.SendIntentException e) {
e.printStackTrace();
}
} else {
Log.i(TAG, "Location services connection failed with code " + connectionResult.getErrorCode());
}
}
I have a public interface that starts the connection to the API:
public void connect()
{
mGoogleApiClient.connect();
Log.d(TAG, "Connection Requested");
}
I can see the above log output file on Android Studio Run Console.
Has anyone else seen this type of problem?
Edit:
Code to build and initialise the client
public myLocation(Context Base, Activity activitiyBase, PendingIntent intent) {
mParentBase = Base;
mParentActivity = activitiyBase;
mParentIntent = intent;
initialLocationService();
}
/**
* Initialize the Location Service and API Client
*/
private void initialLocationService(){
mGoogleApiClient = new GoogleApiClient.Builder(mParentBase)
.addConnectionCallbacks(this)
.addOnConnectionFailedListener(this)
.addApi(LocationServices.API)
.build();
requestLocation = LocationRequest.create()
.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY)
.setInterval(10*1000)
.setFastestInterval(1*1000);
the class implements the following:
public class myLocation implements
GoogleApiClient.ConnectionCallbacks,
GoogleApiClient.OnConnectionFailedListener,
ActivityCompat.OnRequestPermissionsResultCallback,
LocationListener
{
OK. I've put together some code that I hope will help you find your problem. I have this code as a working app on a device. I've used a mix of your code with mine. By comparing the differences, you should be able to narrow down your problem. 1st myLocation class...
public class myLocation implements
GoogleApiClient.ConnectionCallbacks,
GoogleApiClient.OnConnectionFailedListener,
ActivityCompat.OnRequestPermissionsResultCallback,
LocationListener {
private final static String TAG = "myLocation";
private final static int MY_PERMISSION_ACCESS_FINE_LOCATION = 1;
private final static long ONE_SECOND = 1000;
private final static long UPDATE_INTERVAL = ONE_SECOND;
private final static long FASTEST_UPDATE_INTERVAL = ONE_SECOND;
private GoogleApiClient mGoogleApiClient = null;
Context mParentBase;
Activity mParentActivity;
public myLocation(Context Base, Activity activitiyBase) {
mParentBase = Base;
mParentActivity = activitiyBase;
initialLocationService();
}
// you call this an interface in your question but I'm just
// making it a public method which can be called from Activity
public void connect()
{
mGoogleApiClient.connect();
Log.d(TAG, "Connection Requested");
}
#Override
public void onConnected(#Nullable Bundle bundle) {
Log.d(TAG, "OnConnected");
if (PackageManager.PERMISSION_GRANTED ==
(ContextCompat.checkSelfPermission(mParentBase,
android.Manifest.permission.ACCESS_FINE_LOCATION)))
{
Log.d(TAG, "Permission Was Granted");
startLocationUpdates();
} else {
ActivityCompat.requestPermissions(mParentActivity,
new String[]{android.Manifest.permission.ACCESS_FINE_LOCATION},
MY_PERMISSION_ACCESS_FINE_LOCATION);
Log.d(TAG, "Permission Was Requested");
}
}
#Override
public void onConnectionFailed(#NonNull ConnectionResult connectionResult) {
Log.i(TAG, "Connection Failed");
// just logging for now
}
#Override
public void onRequestPermissionsResult(int requestCode,
#NonNull String[] permissions, #NonNull int[] grantResults) {
// loading from Android Studio, not going to worry about this now
}
#Override
public void onConnectionSuspended(int i) {
Log.i(TAG, "Connection Suspended");
// just logging for now, not trying to resolve failure
}
#Override
public void onLocationChanged(Location location) {
Log.i(TAG, "Entered the onLocationChanged() method");
// this calls one or the other private methods that don't
// matter to your problem. I can post them if you like.
if (location != null) {
showLocationInfo(location);
} else {
Log.d(TAG, "Can't get last location");
setAllUnavailable();
}
}
private void initialLocationService() {
if (mGoogleApiClient == null) {
mGoogleApiClient = new GoogleApiClient.Builder(mParentBase)
.addConnectionCallbacks(this)
.addOnConnectionFailedListener(this)
.addApi(LocationServices.API)
.build();
}
}
private void locationRequestUpdates(long interval, long fastestInterval, int priority) {
// remove any previous updates
try {
if(mGoogleApiClient.isConnected()) {
LocationServices.FusedLocationApi
.removeLocationUpdates(mGoogleApiClient, this);
}
} catch (SecurityException e) {
logException("SecurityException", e);
}
// build a new request
LocationRequest locationRequest = new LocationRequest()
.setInterval(interval)
.setFastestInterval(fastestInterval)
.setPriority(priority);
// now send new request
try {
if(mGoogleApiClient.isConnected()) {
LocationServices.FusedLocationApi.requestLocationUpdates(
mGoogleApiClient, locationRequest, this);
}
} catch (SecurityException e) {
logException("SecurityException", e);
}
}
private void startLocationUpdates() {
Location lastLocation = null;
try {
lastLocation = LocationServices.FusedLocationApi.getLastLocation(
mGoogleApiClient);
} catch (SecurityException e) {
logException("SecurityException", e);
}
if (lastLocation != null) {
showLocationInfo(lastLocation);
} else {
Log.d(TAG, "Can't get last location");
setAllUnavailable();
}
locationRequestUpdates(UPDATE_INTERVAL,
FASTEST_UPDATE_INTERVAL,
LocationRequest.PRIORITY_HIGH_ACCURACY);
}
}
In the Activity, in onCreate()...
mMyLocation = new myLocation(getApplicationContext(), this);
and in onStart()...
mMyLocation.connect();
I hope this helps.
I'm trying to implement Google sign in in order to use Wallet, or Pay, and sell a product to the user. I followed the steps from the official guide and I even cloned the project and it has the same issue as mine. The problem is that when I try to get the user's information from the OptionalPendingResult the system throws an IllegalStateException.
First, the user has to go through an Activity that uses a GoogleApiClient initialized this way:
#Override
protected void onCreate(#Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_checkout);
ButterKnife.bind(this);
setSupportActionBar(toolbar);
mGoogleApiClient = new GoogleApiClient.Builder(this)
.addApi(Wallet.API, new Wallet.WalletOptions.Builder().build())
.build();
showProgressDialog();
itemInfo = getIntent().getParcelableExtra(Constants.EXTRA_ITEM_INFO);
}
Afterwards, I show a com.google.android.gms.common.SignInButton in a fragment hosted by an Activity without a GoogleApiClient which I'm implementing on the fragment:
public class LoginFragment extends Fragment implements GoogleApiClient.ConnectionCallbacks,
GoogleApiClient.OnConnectionFailedListener {
public static final int REQUEST_CODE_PICK_ACCOUNT = 1000;
public static final int REQUEST_CODE_RESOLVE_ERR = 1005;
public static final int REQUEST_CODE_SIGN_IN = 1006;
private static final String TAG = "LoginFragment";
private static final String WALLET_SCOPE = "https://www.googleapis.com/auth/payments.make_payments";
private static final String WALLET_SANDBOX_SCOPE = "https://www.googleapis.com/auth/paymentssandbox.make_payments";
#Bind(R.id.sign_in_button)com.google.android.gms.common.SignInButton button;
private ProgressDialog mProgressDialog;
private GoogleApiClient mGoogleApiClient;
private int mLoginAction;
private String userEmail;
public static LoginFragment newInstance(int intentCode) {
LoginFragment fragment = new LoginFragment();
Bundle args = new Bundle();
args.putInt(LoginActivity.EXTRA_ACTION, intentCode);
fragment.setArguments(args);
return fragment;
}
public LoginFragment() {}
#Override public void onCreate(#Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Bundle args = getArguments();
if (args != null) {
mLoginAction = args.getInt(LoginActivity.EXTRA_ACTION);
}
if(savedInstanceState != null) {
userEmail = savedInstanceState.getString("email");
}
GoogleSignInOptions gso = new GoogleSignInOptions.Builder(GoogleSignInOptions.DEFAULT_SIGN_IN)
.requestEmail()
.requestProfile()
.requestScopes(new Scope(WALLET_SCOPE))
// .requestIdToken(getString(R.string.client_id_test))
.build();
mGoogleApiClient = new GoogleApiClient.Builder(getActivity())
.addApi(Auth.GOOGLE_SIGN_IN_API, gso)
.build();
}
#Override public View onCreateView(LayoutInflater inflater, #Nullable ViewGroup container,
#Nullable Bundle savedInstanceState) {
super.onCreateView(inflater, container, savedInstanceState);
View v = inflater.inflate(R.layout.fragment_login, container, false);
ButterKnife.bind(this, v);
button.setSize(SignInButton.SIZE_WIDE);
if(savedInstanceState != null && userEmail.isEmpty())
userEmail = savedInstanceState.getString("email");
button.setClickable(true);
return v;
}
#Override public void onStart() {
super.onStart();
mGoogleApiClient.connect();
}
#Override public void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
outState.putString("email", userEmail);
}
#Override public void onStop() {
super.onStop();
mGoogleApiClient.disconnect();
}
#Override public void onActivityResult(int requestCode, int resultCode, Intent data) {
switch (requestCode) {
case REQUEST_CODE_SIGN_IN:
logIn(data);
button.setClickable(true);
break;
case REQUEST_CODE_PICK_ACCOUNT:
if (resultCode == Activity.RESULT_OK) {
userEmail = data.getStringExtra(AccountManager.KEY_ACCOUNT_NAME);
getUsername();
} else if (resultCode == Activity.RESULT_CANCELED) {
showToast(getString(R.string.please_select_account));
}
default:
super.onActivityResult(requestCode, resultCode, data);
break;
}
}
#Override public void onDestroyView() {
super.onDestroyView();
ButterKnife.unbind(this);
mGoogleApiClient = null;
}
#OnClick(R.id.sign_in_button) public void onSignIn() {
if(button.isClickable()) {
button.setClickable(false);
Intent intent = Auth.GoogleSignInApi.getSignInIntent(mGoogleApiClient);
startActivityForResult(intent, REQUEST_CODE_SIGN_IN);
}
}
#Override public void onConnected(#Nullable Bundle bundle) {
if (mLoginAction == LoginActivity.Action.LOGOUT) {
logOut();
}
}
#Override public void onConnectionSuspended(int i) {}
#Override public void onConnectionFailed(#NonNull ConnectionResult connectionResult) {
Log.e(TAG, "onConnectionFailed, error code:" + connectionResult.getErrorCode());
switch (connectionResult.getErrorCode()) {
case ConnectionResult.SERVICE_DISABLED:
showToast(getString(R.string.error_gps_service_disabled));
break;
case ConnectionResult.SERVICE_INVALID:
showToast(getString(R.string.error_gps_service_invalid));
break;
case ConnectionResult.SERVICE_VERSION_UPDATE_REQUIRED:
showToast(getString(R.string.error_gps_service_update));
break;
}
}
private void showToast(String message) {
Toast.makeText(getActivity(), "Failed: " + message, Toast.LENGTH_SHORT).show();
}
private void logIn(Intent data) {
OptionalPendingResult<GoogleSignInResult> opr = Auth.GoogleSignInApi.silentSignIn(mGoogleApiClient);
if (opr.isDone()) {
try {
GoogleSignInResult signInResult = opr.get();
GoogleSignInAccount gsa = signInResult.getSignInAccount();
Toast.makeText(getActivity(), getString(R.string.welcome_user, gsa.getDisplayName()),
Toast.LENGTH_LONG).show();
((MultaJustaApp) getActivity().getApplication()).login(gsa.getEmail(), gsa.getIdToken());
success = true;
} catch (IllegalStateException e) {
e.printStackTrace();
showToast(getString(R.string.error_sign_in));
}
} else {
showToast(getString(R.string.network_error));
}
if(success) {
getActivity().setResult(Activity.RESULT_OK);
getActivity().finish();
}
}
}
Worth mentioning that right after the creation of the opr, when I check it on watch variables it has a Status{statusCode=INTERNAL_ERROR, resolution=null} property, and of course when opr.get() is called the IllegalStateException is thrown because The Result has already been consumed. I've tried everything, the API is enabled in my console, the checksum from the keystore is up, and the apiClient is connected at the time of the request. I'm having the problem on both emulators and physical devices. I'm desperate. I really appreciate any help.
My OAth client IDs:
Thanks
First of all, you should not get IllegalStateException unless you call opr.get() before isDone() or call it multiple times (no matter it's a failure or success result):
https://developers.google.com/android/reference/com/google/android/gms/common/api/OptionalPendingResult.html#get()
Could you double check your code / paste your exact code here?
Secondly, the most common issue for INTERNAL_ERROR is missing the right OAuth2 client registration. (Unfortunately, for now, the status code is INTERNAL_ERROR 8, which is not helpful.) E.g. Take a look at this thread:
Occured an INTERNAL_ERROR when requestEmail from GoogleSignInOptions Android. Since you already added the Wallet scope, if missing OAuth2 registration, you will see "unregistered Android application" in the consent dialog. (I attached a screenshot at the end)
Thirdly, you can save a lot of boiler plate code by using enableAutoManage. Please check out the official doc:
https://developers.google.com/identity/sign-in/android/sign-in
(e.g. all those error handling in your onConnectionFailed handler, connect() / disconnect() will both be called automatically). And it's okay to call Auth.GoogleSignInApi.silentSignIn() in your onActivityResult. But a simpler way to get the result is:
GoogleSignInResult result = Auth.GoogleSignInApi.getSignInResultFromIntent(data);
I coded an Android Game in Java using Android Studio. Now I want to exchange the players highscore online, via the GoogleApi. So I initialize a GoogleApiClient in my onCreate function:
googleApi = new GoogleApiClient.Builder(FullscreenActivity.this)
.addApi(Games.API)
.addOnConnectionFailedListener(this)
.addConnectionCallbacks(this)
.build();
Where googleApiis a public GoogleApiClient variable.
Then there are:
#Override
protected void onStart() {
super.onStart();
Log.e("Connected?", String.valueOf(googleApi.isConnected()));
googleApi.connect();
}
#Override
public void onConnectionFailed(ConnectionResult result) {
Log.d("ConnectionFailed", String.valueOf(result));
if (result.hasResolution()) {
try {
// !!!
result.startResolutionForResult(this, REQUEST_CODE_RESOLVE_ERR);
} catch (IntentSender.SendIntentException e) {
googleApi.connect();
}
}
}
#Override
public void onConnected(Bundle bundle) {
if(!started){
started = true;
setContentView(new Game(this));
}
}
#Override
public void onConnectionSuspended(int i) {
if(!started){
started = true;
this.setContentView(new Game(this));
}
}
The output of onConnectionFailed(...) says: D/ConnectionFailed: ConnectionResult{statusCode=SIGN_IN_REQUIRED, resolution=PendingIntent{2b5bddee: android.os.BinderProxy#7d0328f}, message=null}
On my mobile the Google Play Games Login window showed up, and I logged in. Then a rotating progress circle was showing, and it disappeared. The onConnected(...) function never got called.
What to add/remove/edit?
This is most likely not a duplicate, because I did not find a working solution for several other questions, that equal in content.
During the signin process, there can be multiple calls to onConnectionFailed. Have you looked at the samples in GitHub: https://github.com/playgameservices/android-basic-samples/tree/master/BasicSamples ?
In the samples onConnectionFailed is implemented as:
public void onConnectionFailed(ConnectionResult connectionResult) {
Log.d(TAG, "onConnectionFailed");
if (mIsResolving) {
// The application is attempting to resolve this connection failure already.
Log.d(TAG, "onConnectionFailed: already resolving");
return;
}
if (mSignInClicked || mAutoStartSignIn) {
mSignInClicked = false;
mAutoStartSignIn = false;
// Attempt to resolve the connection failure.
Log.d(TAG, "onConnectionFailed: begin resolution.");
mIsResolving = resolveConnectionFailure(this, mGoogleApiClient,
connectionResult, RC_SIGN_IN, getString(R.string.signin_other_error));
}
updateUI();
}
And resolveConnectionFailure is:
public static boolean resolveConnectionFailure(Activity activity,
GoogleApiClient client, ConnectionResult result, int requestCode,
String fallbackErrorMessage) {
if (result.hasResolution()) {
try {
result.startResolutionForResult(activity, requestCode);
return true;
} catch (IntentSender.SendIntentException e) {
// The intent was canceled before it was sent. Return to the default
// state and attempt to connect to get an updated ConnectionResult.
client.connect();
return false;
}
} else {
// not resolvable... so show an error message
int errorCode = result.getErrorCode();
Dialog dialog = GooglePlayServicesUtil.getErrorDialog(errorCode,
activity, requestCode);
if (dialog != null) {
dialog.show();
} else {
// no built-in dialog: show the fallback error message
showAlert(activity, fallbackErrorMessage);
}
return false;
}
}
I am trying to design a good architecture for implementing Google API Services.
The current documentation looks like this:
public class MainActivity extends ActionBarActivity {
public static final String TAG = "BasicHistoryApi";
private static final int REQUEST_OAUTH = 1;
private static final String DATE_FORMAT = "yyyy.MM.dd HH:mm:ss";
/**
* Track whether an authorization activity is stacking over the current activity, i.e. when
* a known auth error is being resolved, such as showing the account chooser or presenting a
* consent dialog. This avoids common duplications as might happen on screen rotations, etc.
*/
private static final String AUTH_PENDING = "auth_state_pending";
private boolean authInProgress = false;
private GoogleApiClient mClient = null;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// This method sets up our custom logger, which will print all log messages to the device
// screen, as well as to adb logcat.
initializeLogging();
if (savedInstanceState != null) {
authInProgress = savedInstanceState.getBoolean(AUTH_PENDING);
}
buildFitnessClient();
}
/**
* Build a {#link GoogleApiClient} that will authenticate the user and allow the application
* to connect to Fitness APIs. The scopes included should match the scopes your app needs
* (see documentation for details). Authentication will occasionally fail intentionally,
* and in those cases, there will be a known resolution, which the OnConnectionFailedListener()
* can address. Examples of this include the user never having signed in before, or
* having multiple accounts on the device and needing to specify which account to use, etc.
*/
private void buildFitnessClient() {
// Create the Google API Client
mClient = new GoogleApiClient.Builder(this)
.addApi(Fitness.HISTORY_API)
.addScope(new Scope(Scopes.FITNESS_ACTIVITY_READ_WRITE))
.addConnectionCallbacks(
new GoogleApiClient.ConnectionCallbacks() {
#Override
public void onConnected(Bundle bundle) {
Log.i(TAG, "Connected!!!");
// Now you can make calls to the Fitness APIs. What to do?
// Look at some data!!
new InsertAndVerifyDataTask().execute();
}
#Override
public void onConnectionSuspended(int i) {
// If your connection to the sensor gets lost at some point,
// you'll be able to determine the reason and react to it here.
if (i == ConnectionCallbacks.CAUSE_NETWORK_LOST) {
Log.i(TAG, "Connection lost. Cause: Network Lost.");
} else if (i == ConnectionCallbacks.CAUSE_SERVICE_DISCONNECTED) {
Log.i(TAG, "Connection lost. Reason: Service Disconnected");
}
}
}
)
.addOnConnectionFailedListener(
new GoogleApiClient.OnConnectionFailedListener() {
// Called whenever the API client fails to connect.
#Override
public void onConnectionFailed(ConnectionResult result) {
Log.i(TAG, "Connection failed. Cause: " + result.toString());
if (!result.hasResolution()) {
// Show the localized error dialog
GooglePlayServicesUtil.getErrorDialog(result.getErrorCode(),
MainActivity.this, 0).show();
return;
}
// The failure has a resolution. Resolve it.
// Called typically when the app is not yet authorized, and an
// authorization dialog is displayed to the user.
if (!authInProgress) {
try {
Log.i(TAG, "Attempting to resolve failed connection");
authInProgress = true;
result.startResolutionForResult(MainActivity.this,
REQUEST_OAUTH);
} catch (IntentSender.SendIntentException e) {
Log.e(TAG,
"Exception while starting resolution activity", e);
}
}
}
}
)
.build();
}
#Override
protected void onStart() {
super.onStart();
// Connect to the Fitness API
Log.i(TAG, "Connecting...");
mClient.connect();
}
#Override
protected void onStop() {
super.onStop();
if (mClient.isConnected()) {
mClient.disconnect();
}
}
.... // MORE CODE
}
This looks really ugly inside an Activity, what if I have multiple Activities using Google API Services.
Would it be possible to move everything to a Client.java class that just handles creation of a GoogleApiClient object.
How would I pass an activity context parameter to GoogleApiClient.Builder(this)? Should I use an event bus driven system that sends off context values from each activity to the client and builds it each time?
This is pretty ugly, any way I can trim this code so I don't have to copy it everywhere in like 30 activities?
How about a manager class GoogleApiManager.java that would handle all that for me? What sorts of interfaces would I need to implement on this?
Can I instead store inside an application class instead?
Would appreciate any help on this.
You are going to have to mess around with the code to get it all working correctly. I don't have google api client hooked up so I can't debug.
You could create a separate class like below
public class BuildFitnessClient {
private static boolean mAuthInProgress;
private static final String TAG = "BasicHistoryApi";
private static final int REQUEST_OAUTH = 1;
public static GoogleApiClient googleApiClient(final Activity activity, boolean authInProgress) {
mAuthInProgress = authInProgress;
return new GoogleApiClient.Builder(activity)
.addApi(Fitness.HISTORY_API)
.addScope(new Scope(Scopes.FITNESS_ACTIVITY_READ_WRITE))
.addConnectionCallbacks(
new GoogleApiClient.ConnectionCallbacks() {
#Override
public void onConnected(Bundle bundle) {
mCallbacks.connected();
}
#Override
public void onConnectionSuspended(int i) {
if (i == GoogleApiClient.ConnectionCallbacks.CAUSE_NETWORK_LOST) {
Log.i(TAG, "Connection lost. Cause: Network Lost.");
}
}
}
)
.addOnConnectionFailedListener(
new GoogleApiClient.OnConnectionFailedListener() {
// Called whenever the API client fails to connect.
#Override
public void onConnectionFailed(ConnectionResult result) {
Log.i(TAG, "Connection failed. Cause: " + result.toString());
if (!result.hasResolution()) {
// Show the localized error dialog
GooglePlayServicesUtil.getErrorDialog(result.getErrorCode(),
activity, 0).show();
return;
}
if (!mAuthInProgress) {
try {
Log.i(TAG, "Attempting to resolve failed connection");
mAuthInProgress = true;
result.startResolutionForResult(activity,
REQUEST_OAUTH);
} catch (IntentSender.SendIntentException e) {
Log.e(TAG,
"Exception while starting resolution activity", e);
}
}
}
}
)
.build();
}
/**
* Interface to communicate to the parent activity (MainActivity.java)
*/
private static MyCallbacks mCallbacks;
public interface MyCallbacks {
void connected();
}
public void onAttach(Activity activity) {
try {
mCallbacks = (MyCallbacks) activity;
} catch (ClassCastException e) {
throw new ClassCastException("Activity must implement Fragment One.");
}
}
}
Then in your Activity you could call it like:
public class TestingActivity extends AppCompatActivity implements BuildFitnessClient.MyCallbacks {
GoogleApiClient mClient;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_testing);
new BuildFitnessClient().onAttach(this);
mClient = new BuildFitnessClient().googleApiClient(this, true);
}
#Override
protected void onStart() {
super.onStart();
mClient.connect();
}
#Override
protected void onStop() {
super.onStop();
if (mClient.isConnected()) {
mClient.disconnect();
}
}
#Override
public void connected() {
Log.e("Connected", "Connected");
new InsertAndVerifyDataTask().execute();
}
}
I am trying to give my users the option to sign in with either Google or Facebook. So far I found an example to implement a Google Sign in Flow, but I am confused if I can implement a similar Facebook Login Flow within the same Activity.
Anyone have an Idea as to handle the Logins? I was thinking about potentially defining a class to handle the Login Flows for both Google / Facebook, and perhaps just check to see which is being used when the app launches. Any Ideas?
public class MainActivity extends Activity implements ConnectionCallbacks,
OnConnectionFailedListener, OnClickListener, OnAccessRevokedListener {
private static final String TAG = "MainActivity";
// A magic number we will use to know that our sign-in error
// resolution activity has completed.
private static final int OUR_REQUEST_CODE = 49404;
// The core Google+ client.
private PlusClient mPlusClient;
// A flag to stop multiple dialogues appearing for the user.
private boolean mResolveOnFail;
// We can store the connection result from a failed connect()
// attempt in order to make the application feel a bit more
// responsive for the user.
private ConnectionResult mConnectionResult;
// A progress dialog to display when the user is connecting in
// case there is a delay in any of the dialogs being ready.
private ProgressDialog mConnectionProgressDialog;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
// We pass through this for all three arguments, specifying the:
// 1. Context
// 2. Object to call onConnected and onDisconnected on
// 3. Object to call onConnectionFailed on
mPlusClient = new PlusClient.Builder(this, this, this)
.setVisibleActivities("http://schemas.google.com/BuyActivity")
.build();
// We use mResolveOnFail as a flag to say whether we should trigger
// the resolution of a connectionFailed ConnectionResult.
mResolveOnFail = false;
// Connect our sign in, sign out and disconnect buttons.
findViewById(R.id.sign_in_button).setOnClickListener(this);
findViewById(R.id.sign_out_button).setOnClickListener(this);
findViewById(R.id.sign_out_button).setVisibility(View.GONE);
findViewById(R.id.authButton).setOnClickListener(this);
// Configure the ProgressDialog that will be shown if there is a
// delay in presenting the user with the next sign in step.
mConnectionProgressDialog = new ProgressDialog(this);
mConnectionProgressDialog.setMessage("Signing in...");
}
#Override
protected void onStart() {
super.onStart();
Log.v(TAG, "Start");
// Every time we start we want to try to connect. If it
// succeeds we'll get an onConnected() callback. If it
// fails we'll get onConnectionFailed(), with a result!
mPlusClient.connect();
}
#Override
protected void onStop() {
super.onStop();
Log.v(TAG, "Stop");
// It can be a little costly to keep the connection open
// to Google Play Services, so each time our activity is
// stopped we should disconnect.
mPlusClient.disconnect();
}
#Override
public void onConnectionFailed(ConnectionResult result) {
Log.v(TAG, "ConnectionFailed");
// Most of the time, the connection will fail with a
// user resolvable result. We can store that in our
// mConnectionResult property ready for to be used
// when the user clicks the sign-in button.
if (result.hasResolution()) {
mConnectionResult = result;
if (mResolveOnFail) {
// This is a local helper function that starts
// the resolution of the problem, which may be
// showing the user an account chooser or similar.
startResolution();
}
}
}
#Override
public void onConnected(Bundle bundle) {
// Yay! We can get the oAuth 2.0 access token we are using.
Log.v(TAG, "Connected. Yay!");
// Turn off the flag, so if the user signs out they'll have to
// tap to sign in again.
mResolveOnFail = false;
// Hide the progress dialog if its showing.
mConnectionProgressDialog.dismiss();
// Hide the sign in button, show the sign out buttons.
findViewById(R.id.sign_in_button).setVisibility(View.GONE);
findViewById(R.id.sign_out_button).setVisibility(View.VISIBLE);
// Retrieve the oAuth 2.0 access token.
final Context context = this.getApplicationContext();
AsyncTask task = new AsyncTask() {
#Override
protected Object doInBackground(Object... params) {
String scope = "oauth2:" + Scopes.PLUS_LOGIN;
try {
// We can retrieve the token to check via
// tokeninfo or to pass to a service-side
// application.
String token = GoogleAuthUtil.getToken(context,
mPlusClient.getAccountName(), scope);
} catch (UserRecoverableAuthException e) {
// This error is recoverable, so we could fix this
// by displaying the intent to the user.
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} catch (GoogleAuthException e) {
e.printStackTrace();
}
return null;
}
};
task.execute((Void) null);
// THIS IS TO CONNECT TO NAVI ACTIVITY AFTER YOU CONNECT Also makes it
// so you cannot go back to main activity
/*
* if (mPlusClient.isConnected()) { Intent intent = new Intent(this,
* NaviActivity.class); startActivity(intent); } finish();
*/
}
#Override
public void onDisconnected() {
// Bye!
Log.v(TAG, "Disconnected. Bye!");
}
protected void onActivityResult(int requestCode, int responseCode,
Intent intent) {
Log.v(TAG, "ActivityResult: " + requestCode);
if (requestCode == OUR_REQUEST_CODE && responseCode == RESULT_OK) {
// If we have a successful result, we will want to be able to
// resolve any further errors, so turn on resolution with our
// flag.
mResolveOnFail = true;
// If we have a successful result, lets call connect() again. If
// there are any more errors to resolve we'll get our
// onConnectionFailed, but if not, we'll get onConnected.
mPlusClient.connect();
} else if (requestCode == OUR_REQUEST_CODE && responseCode != RESULT_OK) {
// If we've got an error we can't resolve, we're no
// longer in the midst of signing in, so we can stop
// the progress spinner.
mConnectionProgressDialog.dismiss();
}
}
#Override
public void onClick(View view) {
switch (view.getId()) {
case R.id.sign_in_button:
Log.v(TAG, "Tapped sign in");
if (!mPlusClient.isConnected()) {
// Show the dialog as we are now signing in.
mConnectionProgressDialog.show();
// Make sure that we will start the resolution (e.g. fire the
// intent and pop up a dialog for the user) for any errors
// that come in.
mResolveOnFail = true;
// We should always have a connection result ready to resolve,
// so we can start that process.
if (mConnectionResult != null) {
startResolution();
} else {
// If we don't have one though, we can start connect in
// order to retrieve one.
mPlusClient.connect();
}
}
break;
case R.id.sign_out_button:
Log.v(TAG, "Tapped sign out");
// We only want to sign out if we're connected.
if (mPlusClient.isConnected()) {
// Clear the default account in order to allow the user
// to potentially choose a different account from the
// account chooser.
mPlusClient.clearDefaultAccount();
// Disconnect from Google Play Services, then reconnect in
// order to restart the process from scratch.
mPlusClient.disconnect();
mPlusClient.connect();
// Hide the sign out buttons, show the sign in button.
findViewById(R.id.sign_in_button).setVisibility(View.VISIBLE);
findViewById(R.id.sign_out_button).setVisibility(View.GONE);
}
break;
// THIS SHOULD NOT BE NEEDED, MUST SWITCH ACTIVITIES UPON AUTHORIZATION
case R.id.authButton:
Log.v(TAG, "Switch Activities");
if (mPlusClient.isConnected()) {
Intent intent = new Intent(view.getContext(),
NaviActivity.class);
view.getContext().startActivity(intent);
}
break;
default:
// Unknown id.
}
}
#Override
public void onAccessRevoked(ConnectionResult status) {
// mPlusClient is now disconnected and access has been revoked.
// We should now delete any data we need to comply with the
// developer properties. To reset ourselves to the original state,
// we should now connect again. We don't have to disconnect as that
// happens as part of the call.
mPlusClient.connect();
// Hide the sign out buttons, show the sign in button.
findViewById(R.id.sign_in_button).setVisibility(View.VISIBLE);
findViewById(R.id.sign_out_button).setVisibility(View.GONE);
}
/**
* A helper method to flip the mResolveOnFail flag and start the resolution
* of the ConnenctionResult from the failed connect() call.
*/
private void startResolution() {
try {
// Don't start another resolution now until we have a
// result from the activity we're about to start.
mResolveOnFail = false;
// If we can resolve the error, then call start resolution
// and pass it an integer tag we can use to track. This means
// that when we get the onActivityResult callback we'll know
// its from being started here.
mConnectionResult.startResolutionForResult(this, OUR_REQUEST_CODE);
} catch (SendIntentException e) {
// Any problems, just try to connect() again so we get a new
// ConnectionResult.
mPlusClient.connect();
}
}
}
set both fragments (facebook and google) in the layout that you use as login and in another to receive the session validated
<com.facebook.widget.LoginButton
android:id="#+id/authButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:layout_marginTop="30dp" />
<com.google.android.gms.common.SignInButton
android:id="#+id/sign_in_button"
android:layout_below="#id/authButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
then use al functions required by each one
public class MainActivity extends Activity implements ConnectionCallbacks,OnConnectionFailedListener {
//google
private PlusClient plusClient;
private SignInButton btnSignIn;
private ProgressDialog connectionProgressDialog;
private ConnectionResult connectionResult;
private static final int REQUEST_CODE_RESOLVE_ERR = 9000;
//face
private LoginButton buttonLoginLogout;
private UiLifecycleHelper uiHelper;
static Usuario appusuario;
static String urldelogin="algo";
private Session.StatusCallback callback = new Session.StatusCallback() {
#Override
public void call(Session session, SessionState state, Exception exception) {
onSessionStateChange(session, state, exception);
if (session.isOpened()) {
Log.e("usuario", "si hay sesion");
// make request to the /me API
Request.newMeRequest(session, new Request.GraphUserCallback() {
// callback after Graph API response with user object
#Override
public void onCompleted(GraphUser user, Response response) {
if (user != null) {
Log.e("usuario", "si hay usuario");
buildUserInfoDisplay(user);
//start another activity
}
}
}).executeAsync();
}
}
private void onSessionStateChange(Session session, SessionState state,
Exception exception) {
// TODO Auto-generated method stub
}
};
#Override
public void onResume() {
super.onResume();
uiHelper.onResume();
}
#Override
public void onPause() {
super.onPause();
uiHelper.onPause();
}
#Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
uiHelper.onActivityResult(requestCode, resultCode, data);
if (requestCode == REQUEST_CODE_RESOLVE_ERR &&
resultCode == RESULT_OK)
{
connectionResult = null;
plusClient.connect();
}
}
#Override
public void onDestroy() {
super.onDestroy();
uiHelper.onDestroy();
}
#Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
uiHelper.onSaveInstanceState(outState);
}
public static void buildUserInfoDisplay(GraphUser user) {
appusuario=new Usuario(user.getName(),user.getUsername());
}
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
uiHelper = new UiLifecycleHelper(this, callback);
uiHelper.onCreate(savedInstanceState);
buttonLoginLogout = (LoginButton)findViewById(R.id.authButton);
buttonLoginLogout.setReadPermissions(Arrays.asList("user_status"));
btnSignIn = (SignInButton)findViewById(R.id.sign_in_button);
buttonLoginLogout.setVisibility(View.VISIBLE);
btnSignIn.setVisibility(View.VISIBLE);
plusClient = new PlusClient.Builder(this, this, this).setActions("http://schemas.google.com/AddActivity", "http://schemas.google.com/BuyActivity")
.build();
connectionProgressDialog = new ProgressDialog(this);
connectionProgressDialog.setMessage("Conectando...");
btnSignIn.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View view)
{
if (!plusClient.isConnected())
{
if (connectionResult == null)
{
connectionProgressDialog.show();
}
else
{
try
{
connectionResult.startResolutionForResult(
MainActivity.this,
REQUEST_CODE_RESOLVE_ERR);
}
catch (SendIntentException e)
{
connectionResult = null;
plusClient.connect();
}
}
}
}
});
}
#Override
protected void onStart()
{
super.onStart();
plusClient.connect();
}
#Override
protected void onStop()
{
super.onStop();
plusClient.disconnect();
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.main, menu);
return true;
}
#Override
public void onConnected(Bundle connectionHint)
{
connectionProgressDialog.dismiss();
//nombre
String accountName = plusClient.getAccountName();
//cuenta con mail
Person accountperson=plusClient.getCurrentPerson();
String personName = accountperson.getDisplayName();
Log.e("Google +", "Conectado");
//start another activity
}
#Override
public void onDisconnected()
{
Log.e("Google +", "Desconectado");
}
#Override
public void onConnectionFailed(ConnectionResult result) {
// TODO Auto-generated method stub
if (connectionProgressDialog.isShowing())
{
if (result.hasResolution())
{
try
{
result.startResolutionForResult(this,
REQUEST_CODE_RESOLVE_ERR);
}
catch (SendIntentException e)
{
plusClient.connect();
}
}
}
connectionResult = result;
}
}
in the new activity place the same functions to validate the sesion and use
if (session.isOpened()) { }
to hide google login button or
public void onConnected(Bundle connectionHint)
{
}
to hide facebook login button