I have this activity:
public class AMLoginActivity extends Activity implements IAsyncResponse {
public static int finished;
private final String TAG = "AMLoginActivity";
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
finished = 0;
Intent i = new Intent(AMLoginActivity.this, GDLoginActivity.class);
i.putExtra("response", this);
AMLoginActivity.this.startActivity(i);
}
public void processFinish(){
finished++;
Log.i(TAG, "Number finished: " + finished);
if(finished == 1){
Log.i(TAG, "All finished");
AMLoginActivity.this.finish();
Log.i(TAG, "Finish called");
}
}
Which calls the GDLoginActivity to login to google drive. It can be seen below:
public class GDLoginActivity extends Activity implements GoogleApiClient.ConnectionCallbacks,
GoogleApiClient.OnConnectionFailedListener {
private static final String TAG = "GDLoginActivity";
private static final int REQUEST_CODE_RESOLUTION = 3;
private static GoogleApiClient mGoogleApiClient;
#Override
protected void onResume() {
super.onResume();
if (mGoogleApiClient == null) {
// Create the API client and bind it to an instance variable.
// We use this instance as the callback for connection and connection
// failures.
// Since no account name is passed, the user is prompted to choose.
mGoogleApiClient = new GoogleApiClient.Builder(this)
.addApi(Drive.API)
.addScope(Drive.SCOPE_FILE)
.addConnectionCallbacks(this)
.addOnConnectionFailedListener(this)
.build();
Log.i(TAG, "New GDClient created");
}
// Connect the client.
mGoogleApiClient.connect();
}
#Override
protected void onPause() {
if (mGoogleApiClient != null) {
mGoogleApiClient.disconnect();
}
super.onPause();
}
#Override
public void onConnected(Bundle connectionHint) {
Log.i(TAG, "API client connected.");
IAsyncResponse response = (IAsyncResponse) getIntent().getSerializableExtra("response");
Log.i(TAG, "Process finish");
response.processFinish();
finish();
}
#Override
public void onConnectionSuspended(int cause) {
Log.i(TAG, "GoogleApiClient connection suspended");
}
#Override
public void onConnectionFailed(ConnectionResult result) {
// Called whenever the API client fails to connect.
Log.i(TAG, "GoogleApiClient connection failed: " + result.toString());
if (!result.hasResolution()) {
// show the localized error dialog.
GoogleApiAvailability.getInstance().getErrorDialog(this, result.getErrorCode(), 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.
try {
result.startResolutionForResult(this, REQUEST_CODE_RESOLUTION);
} catch (IntentSender.SendIntentException e) {
Log.e(TAG, "Exception while starting resolution activity", e);
}
}
public static GoogleApiClient getGoogleApiClient(){
return mGoogleApiClient;
}
}
The issue is that when the GDLoginActivity connects and finish()'s, it should increment finish by 1 and and also finish the AMLoginActivity. It does increment by 1 and call finish() in processFinish(), but nothing happens and AMLoginActivity doesn't actually close (i.e. onDestroy() is never called), so i'm just left with a blank screen. If I remove GDLoginActivity and just call processFinish() instead, then AMLoginActivity finishes just fine, so I assume it has something to do with GDLoginActivity, but this is happening with other similar activities too. Any ideas?
Edit: Also if I hit the back button on the blank screen, then it calls the onDestroy() method of AMLoginActivity and goes to the activity I want, if that hints a clue at what is going on?
It looks like you're finishing them in a weird order. Try finishing the visible activity before you finish the one that started it.
#Override
public void onConnected(Bundle connectionHint) {
Log.i(TAG, "API client connected.");
IAsyncResponse response = (IAsyncResponse) getIntent().getSerializableExtra("response");
Log.i(TAG, "Process finish");
//finishes the previous activity
response.processFinish();
//finishes the visible activity
finish();
//try flipping this order ^
}
You could use startActivitForResult() if you're trying to finish one activity after another has finished.
Related
I am struggling with a problem to display my reverse geocoding results automatically. It works fine when I click button to get location, but I want it to simply display the location automatically when the app is loaded.
My code is in a Java class called geocoding, eventually i want to display this code on a marker on my map, which i have already created.
but this thread is to eliminate the button and display location as son as map loads.
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main); // uses layout from mainactivity
mResultReceiver = new AddressResultReceiver(new Handler());
mLocationAddressTextView = (TextView) findViewById(R.id.location_address_view);
mProgressBar = (ProgressBar) findViewById(R.id.progress_bar);
mFetchAddressButton = (Button) findViewById(R.id.fetch_address_button);
// Set defaults, then update using values stored in the Bundle.
mAddressRequested = false;
mAddressOutput = "";
updateValuesFromBundle(savedInstanceState);
updateUIWidgets();
buildGoogleApiClient();
}
public void buttonOnClick(View view) { // this links the maps activity via the XML layout file
startActivity(new Intent(Geocode.this, MapsActivity.class));
}
/**
* Updates fields based on data stored in the bundle.
*/
private void updateValuesFromBundle(Bundle savedInstanceState) {
if (savedInstanceState != null) {
// Check savedInstanceState to see if the address was previously requested.
if (savedInstanceState.keySet().contains(ADDRESS_REQUESTED_KEY)) {
mAddressRequested = savedInstanceState.getBoolean(ADDRESS_REQUESTED_KEY);
}
// Check savedInstanceState to see if the location address string was previously found
// and stored in the Bundle. If it was found, display the address string in the UI.
if (savedInstanceState.keySet().contains(LOCATION_ADDRESS_KEY)) {
mAddressOutput = savedInstanceState.getString(LOCATION_ADDRESS_KEY);
displayAddressOutput();
}
}
}
/**
* Builds a GoogleApiClient. Uses {#code #addApi} to request the LocationServices API.
*/
protected synchronized void buildGoogleApiClient() {
mGoogleApiClient = new GoogleApiClient.Builder(this)
.addConnectionCallbacks(this)
.addOnConnectionFailedListener(this)
.addApi(LocationServices.API)
.build();
}
public void fetchAddressButtonHandler(View view) {
// We only start the service to fetch the address if GoogleApiClient is connected.
if (mGoogleApiClient.isConnected() && mLastLocation != null) {
startIntentService();
}
mAddressRequested = true;
updateUIWidgets();
}
#Override
protected void onStart() {
super.onStart();
mGoogleApiClient.connect();
}
#Override
protected void onStop() {
super.onStop();
if (mGoogleApiClient.isConnected()) {
mGoogleApiClient.disconnect();
}
}
/**
* Runs when a GoogleApiClient object successfully connects.
*/
#Override
public void onConnected(Bundle connectionHint) {
// Gets the best and most recent location currently available, which may be null
// in rare cases when a location is not available.
if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
// TODO: Consider calling
return;
}
mLastLocation = LocationServices.FusedLocationApi.getLastLocation(mGoogleApiClient);
if (mLastLocation != null) {
// Determine whether a Geocoder is available.
if (!Geocoder.isPresent()) {
Toast.makeText(this, R.string.no_geocoder_available, Toast.LENGTH_LONG).show();
return;
}
if (mAddressRequested) {
startIntentService();
}
}
}
/**
* Creates an intent, adds location data to it as an extra, and starts the intent service for
* fetching an address.
*/
protected void startIntentService() {
// Create an intent for passing to the intent service responsible for fetching the address.
Intent intent = new Intent(this, FetchAddressIntentService.class);
// Pass the result receiver as an extra to the service.
intent.putExtra(Constants.RECEIVER, mResultReceiver);
// Pass the location data as an extra to the service.
intent.putExtra(Constants.LOCATION_DATA_EXTRA, mLastLocation);
startService(intent);
}
#Override
public void onConnectionFailed(ConnectionResult result) {
// Refer to the javadoc for ConnectionResult to see what error codes might be returned in
// onConnectionFailed.
Log.i(TAG, "Connection failed: ConnectionResult.getErrorCode() = " + result.getErrorCode());
}
#Override
public void onConnectionSuspended(int cause) {
// The connection to Google Play services was lost for some reason. We call connect() to
// attempt to re-establish the connection.
Log.i(TAG, "Connection suspended");
mGoogleApiClient.connect();
}
/**
* Updates the address in the UI.
*/
protected void displayAddressOutput() {
mLocationAddressTextView.setText(mAddressOutput);
}
/**
* Toggles the visibility of the progress bar. Enables or disables the Fetch Address button.
*/
private void updateUIWidgets() {
if (mAddressRequested) {
mProgressBar.setVisibility(ProgressBar.VISIBLE);
mFetchAddressButton.setEnabled(false);
} else {
mProgressBar.setVisibility(ProgressBar.GONE);
mFetchAddressButton.setEnabled(true);
}
}
/**
* Shows a toast with the given text.
*/
protected void showToast(String text) {
Toast.makeText(this, text, Toast.LENGTH_SHORT).show();
}
#Override
public void onSaveInstanceState(Bundle savedInstanceState) {
// Save whether the address has been requested.
savedInstanceState.putBoolean(ADDRESS_REQUESTED_KEY, mAddressRequested);
// Save the address string.
savedInstanceState.putString(LOCATION_ADDRESS_KEY, mAddressOutput);
super.onSaveInstanceState(savedInstanceState);
}
/**
* Receiver for data sent from FetchAddressIntentService.
*/
class AddressResultReceiver extends ResultReceiver {
public AddressResultReceiver(Handler handler) {
super(handler);
}
/**
* Receives data sent from FetchAddressIntentService and updates the UI in MainActivity.
*/
#Override
protected void onReceiveResult(int resultCode, Bundle resultData) {
// Display the address string or an error message sent from the intent service.
mAddressOutput = resultData.getString(Constants.RESULT_DATA_KEY);
displayAddressOutput();
// Show a toast message if an address was found.
if (resultCode == Constants.SUCCESS_RESULT) {
showToast(getString(R.string.address_found));
}
// Reset. Enable the Fetch Address button and stop showing the progress bar.
mAddressRequested = false;
updateUIWidgets();
}
}
}
set mAdressRequested from False to True,
so in OnConnected, startIntentService can be called
// Set defaults, then update using values stored in the Bundle.
mAddressRequested = true;
mAddressOutput = "";
updateValuesFromBundle(savedInstanceState);
I been getting an error trying to execute this Android Drive API example googledrive/android-quickstart, the app run fine then shows a windows dialog to select the google account, I select one and in logcat I get this:
I/drive-quickstart﹕ GoogleApiClient connection failed: ConnectionResult{statusCode=SIGN_IN_REQUIRED, resolution=PendingIntent{44c22a28: android.os.BinderProxy#44c1b1c0}}
Then shows the dialog again seems like a infinite loop
I have been already configured the OAuth and other parameters in google developer console.
Here is my code Thanks in advance..
public class CloudPaintActivity extends Activity implements GoogleApiClient.ConnectionCallbacks,
GoogleApiClient.OnConnectionFailedListener {
private static final String TAG = "drive-quickstart";
private static final int REQUEST_CODE_CAPTURE_IMAGE = 1;
private static final int REQUEST_CODE_CREATOR = 2;
private static final int REQUEST_CODE_RESOLUTION = 3;
private GoogleApiClient mGoogleApiClient;
private Bitmap mBitmapToSave;
/**
* Create a new file and save it to Drive.
*/
private void saveFileToDrive() {
// Start by creating a new contents, and setting a callback.
Log.i(TAG, "Creating new contents.");
final Bitmap image = mBitmapToSave;
Drive.DriveApi.newDriveContents(mGoogleApiClient)
.setResultCallback(new ResultCallback<DriveApi.DriveContentsResult>() {
#Override
public void onResult(DriveApi.DriveContentsResult result) {
// If the operation was not successful, we cannot do anything
// and must
// fail.
if (!result.getStatus().isSuccess()) {
Log.i(TAG, "Failed to create new contents.");
return;
}
// Otherwise, we can write our data to the new contents.
Log.i(TAG, "New contents created.");
// Get an output stream for the contents.
OutputStream outputStream = result.getDriveContents().getOutputStream();
// Write the bitmap data from it.
ByteArrayOutputStream bitmapStream = new ByteArrayOutputStream();
image.compress(Bitmap.CompressFormat.PNG, 100, bitmapStream);
try {
outputStream.write(bitmapStream.toByteArray());
} catch (IOException e1) {
Log.i(TAG, "Unable to write file contents.");
}
// Create the initial metadata - MIME type and title.
// Note that the user will be able to change the title later.
MetadataChangeSet metadataChangeSet = new MetadataChangeSet.Builder()
.setMimeType("image/jpeg").setTitle("Android Photo.png").build();
// Create an intent for the file chooser, and start it.
IntentSender intentSender = Drive.DriveApi
.newCreateFileActivityBuilder()
.setInitialMetadata(metadataChangeSet)
.setInitialDriveContents(result.getDriveContents())
.build(mGoogleApiClient);
try {
startIntentSenderForResult(
intentSender, REQUEST_CODE_CREATOR, null, 0, 0, 0);
} catch (IntentSender.SendIntentException e) {
Log.i(TAG, "Failed to launch file chooser.");
}
}
});
}
#Override
protected void onResume() {
super.onResume();
if (mGoogleApiClient == null) {
// Create the API client and bind it to an instance variable.
// We use this instance as the callback for connection and connection
// failures.
// Since no account name is passed, the user is prompted to choose.
mGoogleApiClient = new GoogleApiClient.Builder(this)
.addApi(Drive.API)
.addApi(Plus.API)
.addScope(Drive.SCOPE_FILE)
.addConnectionCallbacks(this)
.addOnConnectionFailedListener(this)
.build();
}
// Connect the client. Once connected, the camera is launched.
mGoogleApiClient.connect();
// if the api client existed, we terminate it
if (mGoogleApiClient != null && mGoogleApiClient.isConnected()) {
Plus.AccountApi.clearDefaultAccount(mGoogleApiClient);
mGoogleApiClient.disconnect();
}
}
#Override
protected void onPause() {
if (mGoogleApiClient != null) {
mGoogleApiClient.disconnect();
}
super.onPause();
}
#Override
protected void onActivityResult(final int requestCode, final int resultCode, final Intent data) {
switch (requestCode) {
case REQUEST_CODE_CAPTURE_IMAGE:
// Called after a photo has been taken.
if (resultCode == Activity.RESULT_OK) {
// Store the image data as a bitmap for writing later.
mBitmapToSave = (Bitmap) data.getExtras().get("data");
}
break;
case REQUEST_CODE_CREATOR:
// Called after a file is saved to Drive.
if (resultCode == RESULT_OK) {
Log.i(TAG, "Image successfully saved.");
mBitmapToSave = null;
// Just start the camera again for another photo.
startActivityForResult(new Intent(MediaStore.ACTION_IMAGE_CAPTURE),
REQUEST_CODE_CAPTURE_IMAGE);
}
break;
}
}
#Override
public void onConnectionFailed(ConnectionResult result) {
// Called whenever the API client fails to connect.
Log.i(TAG, "GoogleApiClient connection failed: " + result.toString());
if (!result.hasResolution()) {
// show the localized error dialog.
GoogleApiAvailability.getInstance().getErrorDialog(this, result.getErrorCode(), 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.
try {
result.startResolutionForResult(this, REQUEST_CODE_RESOLUTION);
} catch (IntentSender.SendIntentException e) {
Log.e(TAG, "Exception while starting resolution activity", e);
}
}
#Override
public void onConnected(Bundle connectionHint) {
Log.i(TAG, "API client connected.");
if (mBitmapToSave == null) {
// This activity has no UI of its own. Just start the camera.
startActivityForResult(new Intent(MediaStore.ACTION_IMAGE_CAPTURE),
REQUEST_CODE_CAPTURE_IMAGE);
return;
}
saveFileToDrive();
}
#Override
public void onConnectionSuspended(int cause) {
Log.i(TAG, "GoogleApiClient connection suspended");
}
}
Try this if you don't need multiple accounts:
public class MainActivity extends AppCompatActivity {
private static final int REQ_CONNECT = 1;
private Activity mAct;
private static GoogleApiClient mGAC;
#Override
protected void onCreate(Bundle bundle) {
super.onCreate(bundle);
mAct = this;
setContentView(R.layout.activity_main);
if (bundle == null) try {
mGAC = new GoogleApiClient.Builder(this)
.addApi(Drive.API)
.addScope(Drive.SCOPE_FILE)
.addConnectionCallbacks(new GoogleApiClient.ConnectionCallbacks() {
#Override public void onConnectionSuspended(int i) { }
#Override
public void onConnected(Bundle bundle) {
Toast.makeText(mAct, "bingo", Toast.LENGTH_LONG).show(); // connected
saveFileToDrive();
}
})
.addOnConnectionFailedListener(new GoogleApiClient.OnConnectionFailedListener() {
#Override
public void onConnectionFailed(ConnectionResult connResult) {
if (connResult != null) {
if (!connResult.hasResolution()) {
int errCode = connResult.getErrorCode();
GooglePlayServicesUtil.getErrorDialog(errCode, mAct, 0).show();
return;
} else try {
connResult.startResolutionForResult(mAct, REQ_CONNECT);
return;
} catch (Exception e) { e.printStackTrace(); }
}
finish(); //--- FAIL - no resolution ---------->>>
}
})
.build();
} catch (Exception e) { e.printStackTrace(); }
}
#Override
protected void onResume() { super.onResume();
mGAC.connect();
}
#Override
protected void onPause() { super.onPause();
mGAC.disconnect();
}
#Override
protected void onActivityResult(int request, int result, Intent data) {
switch (request) {
case REQ_CONNECT:
if (result == RESULT_OK)
mGAC.connect();
else
finish(); //--- FAIL, user cancelled ------------->>>
break;
}
super.onActivityResult(request, result, data);
}
}
If you need to switch multiple accounts, add:
.addApi(Plus.API)
to your builder and call:
Plus.AccountApi.clearDefaultAccount(mGAC);
from wherever (menu for instance). Then create a new instance of mGAC and connect. It will pop up the account selection dialog again. But your app will not know which account the user selected (or created).
If you need to know your current user, you can drop the the Plus.API and manage the GooDrive accounts yourself with Account Picker, but you need to implement an Account Manager and instantiate mGAC with
.setAccountName([ACCOUNT EMAIL])
as seen here (follow the REQ_ACCPICK and see the Account Manager UT.AM).
Good Luck
Based off your error, it seems for whatever reason it fails to sign in. I believe in this case you should check if hasResolution returns true. If so, you can call [startResolutionForResult](https://developers.google.com/android/reference/com/google/android/gms/common/ConnectionResult.html#startResolutionForResult(android.app.Activity, int)) which will prompt the user to sign in.
As far why it fails to sign in, it's a bit difficult to tell. It sounds like you're using the AccountPicker? Perhaps you can try with only a single account signed into the device.
I have observed the behavior you describe when the OAuth 2.0 client ID set up on the Google Cloud console did not match the apk I was trying to run, either by Signing-certificate fingerprint or by Package name.
I am using Google Fit APIs for the first time. I have modified the BasicSensorsApi sample code to calculate steps count. It is working fine, but the problem is when I call GoogleApiClient.disconnect() in onStop() function and then again call GoogleApiClient.connect() in onStart() function, OnDataPointListener stops getting callbacks. I am not unregistering this listener any where.
When I don't call GoogleApiClient.disconnect() it is working fine and I get callbacks event after activity's onStop() function is called.
I am not sure whether I should disconnect GoogleApiClient in onStop() function or not. If yes then how can I solve above problem?
Here is the relavent code:
private void buildFitnessClient() {
// Create the Google API Client
mClient = new GoogleApiClient.Builder(this)
.addApi(Fitness.SENSORS_API)
.addScope(new Scope(Scopes.FITNESS_LOCATION_READ))
.addScope(new Scope((Scopes.FITNESS_ACTIVITY_READ)))
.addScope(new Scope((Scopes.FITNESS_BODY_READ)))
.addConnectionCallbacks(
new GoogleApiClient.ConnectionCallbacks() {
#Override
public void onConnected(Bundle bundle) {
Log.i(TAG, "Connected!!!");
// Now you can make calls to the Fitness APIs.
// Put application specific code here.
findFitnessDataSources();
}
#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 == GoogleApiClient.ConnectionCallbacks.CAUSE_NETWORK_LOST) {
Log.i(TAG, "Connection lost. Cause: Network Lost.");
} else if (i == GoogleApiClient.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();
}
}
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if (requestCode == REQUEST_OAUTH) {
authInProgress = false;
if (resultCode == RESULT_OK) {
// Make sure the app is not already connected or attempting to connect
if (!mClient.isConnecting() && !mClient.isConnected()) {
mClient.connect();
}
}
}
}
#Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
outState.putBoolean(AUTH_PENDING, authInProgress);
}
// [END auth_connection_flow_in_activity_lifecycle_methods]
/**
* Find available data sources and attempt to register on a specific {#link DataType}.
* If the application cares about a data type but doesn't care about the source of the data,
* this can be skipped entirely, instead calling
* {#link com.google.android.gms.fitness.SensorsApi
* #register(GoogleApiClient, SensorRequest, DataSourceListener)},
* where the {#link SensorRequest} contains the desired data type.
*/
private void findFitnessDataSources() {
// [START find_data_sources]
Fitness.SensorsApi.findDataSources(mClient, new DataSourcesRequest.Builder()
// At least one datatype must be specified.
.setDataTypes(DataType.TYPE_STEP_COUNT_CADENCE)
.setDataTypes(DataType.TYPE_STEP_COUNT_CUMULATIVE)
.setDataTypes(DataType.TYPE_STEP_COUNT_DELTA)
// Can specify whether data type is raw or derived.
.setDataSourceTypes(DataSource.TYPE_DERIVED)
.build())
.setResultCallback(new ResultCallback<DataSourcesResult>() {
#Override
public void onResult(DataSourcesResult dataSourcesResult) {
Log.i(TAG, "Result: " + dataSourcesResult.getStatus().toString());
for (DataSource dataSource : dataSourcesResult.getDataSources()) {
Log.i(TAG, "Data source found: " + dataSource.toString());
Log.i(TAG, "Data Source type: " + dataSource.getDataType().getName());
//Let's register a listener to receive Activity data!
if (dataSource.getDataType().equals(DataType.TYPE_STEP_COUNT_CADENCE) && mListener == null) {
Log.i(TAG, "Data source for TYPE_STEP_COUNT_CADENCE found! Registering.");
registerFitnessDataListener(dataSource, DataType.TYPE_STEP_COUNT_CADENCE);
} else if (dataSource.getDataType().equals(DataType.TYPE_STEP_COUNT_CUMULATIVE) && mListener == null) {
Log.i(TAG, "Data source for TYPE_STEP_COUNT_CUMULATIVE found! Registering.");
registerFitnessDataListener(dataSource, DataType.TYPE_STEP_COUNT_CUMULATIVE);
} else if (dataSource.getDataType().equals(DataType.TYPE_STEP_COUNT_DELTA) && mListener == null) {
Log.i(TAG, "Data source for TYPE_STEP_COUNT_DELTA found! Registering.");
registerFitnessDataListener(dataSource, DataType.TYPE_STEP_COUNT_DELTA);
}
}
}
});
// [END find_data_sources]
}
/**
* Register a listener with the Sensors API for the provided {#link DataSource} and
* {#link DataType} combo.
*/
private void registerFitnessDataListener(DataSource dataSource, DataType dataType) {
// [START register_data_listener]
mListener = new OnDataPointListener() {
#Override
public void onDataPoint(DataPoint dataPoint) {
for (Field field : dataPoint.getDataType().getFields()) {
Value val = dataPoint.getValue(field);
Log.i(TAG, "Detected DataPoint field: " + field.getName());
Log.i(TAG, "Detected DataPoint value: " + val);
}
}
};
Fitness.SensorsApi.add(
mClient,
new SensorRequest.Builder()
.setDataSource(dataSource) // Optional but recommended for custom data sets.
.setDataType(dataType) // Can't be omitted.
.setSamplingRate(10, TimeUnit.SECONDS)
.build(),
mListener)
.setResultCallback(new ResultCallback<Status>() {
#Override
public void onResult(Status status) {
if (status.isSuccess()) {
Log.i(TAG, "Listener registered!");
} else {
Log.i(TAG, "Listener not registered.");
}
}
});
// [END register_data_listener]
}
If you are tracking the step counts in the foreground then this is correct behaviour as you are disconnecting the google api client in onstop(). Once GoogleApiClient is disconnected all the listeners will be removed from the GoogleApiClient. But if you wish to track the step counts in the background, then you may have to move your implementation to a service and decide when exactly you want to disconnect from GoogleApiclient.
contrary to the documentation, you have to disconnect in onDestroy not in onStop. connect in onCreate and do nothing in onStop/onStart.
Why?
because an app waiting for onConnect to be called does not prevent onStop being called. What happens is that onStop is called before your app receives the event. then, of course, it disconnects and never gets it.
Here i am doing google + integartion.i am using the following code but i am facing the error which is : onConnectionFailed: ConnectionResult.getErrorCode() = 4.So please anybody help me and tell me what i am doing wrong in this code and provide me the solution for this.i will be very thankful to you.I searched a lot but found nothing.I am using the quick sample of Google plus.There is also another problem i am not able to personal information like birthday etc in this code.
public class GooglePlus extends FragmentActivity implements
ConnectionCallbacks, OnConnectionFailedListener, View.OnClickListener {
String fb_userId, fb_username;
SharedPreferences pref;
SharedPreferences.Editor editor;
private static final int STATE_DEFAULT = 0;
private static final int STATE_SIGN_IN = 1;
private static final int STATE_IN_PROGRESS = 2;
private static final int RC_SIGN_IN = 0;
private static final int DIALOG_PLAY_SERVICES_ERROR = 0;
private static final String SAVED_PROGRESS = "sign_in_progress";
// GoogleApiClient wraps our service connection to Google Play services and
// provides access to the users sign in state and Google's APIs.
private GoogleApiClient mGoogleApiClient;
// We use mSignInProgress to track whether user has clicked sign in.
// mSignInProgress can be one of three values:
//
// STATE_DEFAULT: The default state of the application before the user
// has clicked 'sign in', or after they have clicked
// 'sign out'. In this state we will not attempt to
// resolve sign in errors and so will display our
// Activity in a signed out state.
// STATE_SIGN_IN: This state indicates that the user has clicked 'sign
// in', so resolve successive errors preventing sign in
// until the user has successfully authorized an account
// for our app.
// STATE_IN_PROGRESS: This state indicates that we have started an intent to
// resolve an error, and so we should not start further
// intents until the current intent completes.
private int mSignInProgress;
// Used to store the PendingIntent most recently returned by Google Play
// services until the user clicks 'sign in'.
private PendingIntent mSignInIntent;
// Used to store the error code most recently returned by Google Play
// services
// until the user clicks 'sign in'.
private int mSignInError;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_google_plus);
pref = PreferenceManager.getDefaultSharedPreferences(this);
if (savedInstanceState != null) {
mSignInProgress = savedInstanceState.getInt(SAVED_PROGRESS,
STATE_DEFAULT);
}
mGoogleApiClient = buildGoogleApiClient();
Handler handle = new Handler();
handle.postDelayed(new Runnable() {
#Override
public void run() {
runOnUiThread(new Runnable() {
#Override
public void run() {
// resolveSignInError();
}
});
}
}, 1500);
}
private GoogleApiClient buildGoogleApiClient() {
// When we build the GoogleApiClient we specify where connected and
// connection failed callbacks should be returned, which Google APIs our
// app uses and which OAuth 2.0 scopes our app requests.
return new GoogleApiClient.Builder(this).addConnectionCallbacks(this)
.addOnConnectionFailedListener(this).addApi(Plus.API, null)
.addScope(Plus.SCOPE_PLUS_LOGIN).build();
}
#Override
protected void onStart() {
super.onStart();
mGoogleApiClient.connect();
}
#Override
protected void onStop() {
super.onStop();
if (mGoogleApiClient.isConnected()) {
mGoogleApiClient.disconnect();
}
}
#Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
outState.putInt(SAVED_PROGRESS, mSignInProgress);
}
#Override
public void onConnectionFailed(ConnectionResult result) {
// Refer to the javadoc for ConnectionResult to see what error codes
// might
// be returned in onConnectionFailed.
Log.i("", "onConnectionFailed: ConnectionResult.getErrorCode() = "
+ result.getErrorCode());
if (mSignInProgress != STATE_IN_PROGRESS) {
// We do not have an intent in progress so we should store the
// latest
// error resolution intent for use when the sign in button is
// clicked.
mSignInIntent = result.getResolution();
mSignInError = result.getErrorCode();
if (mSignInProgress == STATE_SIGN_IN) {
// STATE_SIGN_IN indicates the user already clicked the sign in
// button
// so we should continue processing errors until the user is
// signed in
// or they click cancel.
resolveSignInError();
}
}
// In this sample we consider the user signed out whenever they do not
// have
// a connection to Google Play services.
}
#Override
public void onClick(View v) {
// TODO Auto-generated method stub
}
/*
* Starts an appropriate intent or dialog for user interaction to resolve
* the current error preventing the user from being signed in. This could be
* a dialog allowing the user to select an account, an activity allowing the
* user to consent to the permissions being requested by your app, a setting
* to enable device networking, etc.
*/
private void resolveSignInError() {
if (mSignInIntent != null) {
// We have an intent which will allow our user to sign in or
// resolve an error. For example if the user needs to
// select an account to sign in with, or if they need to consent
// to the permissions your app is requesting.
try {
// Send the pending intent that we stored on the most recent
// OnConnectionFailed callback. This will allow the user to
// resolve the error currently preventing our connection to
// Google Play services.
mSignInProgress = STATE_IN_PROGRESS;
startIntentSenderForResult(mSignInIntent.getIntentSender(),
RC_SIGN_IN, null, 0, 0, 0);
} catch (SendIntentException e) {
Log.i("",
"Sign in intent could not be sent: "
+ e.getLocalizedMessage());
// The intent was canceled before it was sent. Attempt to
// connect to
// get an updated ConnectionResult.
mSignInProgress = STATE_SIGN_IN;
mGoogleApiClient.connect();
}
} else {
// Google Play services wasn't able to provide an intent for some
// error types, so we show the default Google Play services error
// dialog which may still start an intent on our behalf if the
// user can resolve the issue.
showDialog(DIALOG_PLAY_SERVICES_ERROR);
}
}
#SuppressWarnings("unused")
#Override
public void onConnected(Bundle arg0) {
// Reaching onConnected means we consider the user signed in.
Log.i("onConnected", "onConnected");
// Retrieve some profile information to personalize our app for the
// user.
Person currentUser = Plus.PeopleApi.getCurrentPerson(mGoogleApiClient);
String personName = currentUser.getDisplayName();
String personPhotoUrl = currentUser.getImage().getUrl();
String personGooglePlusProfile = currentUser.getUrl();
String email = Plus.AccountApi.getAccountName(mGoogleApiClient);
Log.i("personName", personName);
Log.i("email", email);
Log.i("Gender", "" + currentUser.getGender());
Log.i("Birthday", "" + currentUser.getBirthday());
// Indicate that the sign in process is complete.
mSignInProgress = STATE_DEFAULT;
/*
* fb_userId = currentUser.getId(); fb_username =
* currentUser.getDisplayName(); editor = pref.edit();
* editor.putString("fb_userId", fb_userId);
* editor.putString("fb_username", fb_username);
* editor.putString("social_provider", "google +");
*
* editor.putString("gender", currentUser.getGender());
* editor.putString("birthday", currentUser.getBirthday());
*
* editor.putString("device_name", "android");
*
* editor.putString("email",
* Plus.AccountApi.getAccountName(mGoogleApiClient)); editor.commit();
*/
}
#Override
public void onConnectionSuspended(int arg0) {
// The connection to Google Play services was lost for some reason.
// We call connect() to attempt to re-establish the connection or get a
// ConnectionResult that we can attempt to resolve.
mGoogleApiClient.connect();
}
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
switch (requestCode) {
case RC_SIGN_IN:
if (resultCode == RESULT_OK) {
// If the error resolution was successful we should continue
// processing errors.
mSignInProgress = STATE_SIGN_IN;
} else {
// If the error resolution was not successful or the user
// canceled,
// we should stop processing errors.
mSignInProgress = STATE_DEFAULT;
}
if (!mGoogleApiClient.isConnecting()) {
// If Google Play services resolved the issue with a dialog then
// onStart is not called so we need to re-attempt connection
// here.
mGoogleApiClient.connect();
}
break;
}
}
#Override
protected Dialog onCreateDialog(int id) {
switch (id) {
case DIALOG_PLAY_SERVICES_ERROR:
if (GooglePlayServicesUtil.isUserRecoverableError(mSignInError)) {
return GooglePlayServicesUtil.getErrorDialog(mSignInError,
this, RC_SIGN_IN,
new DialogInterface.OnCancelListener() {
#Override
public void onCancel(DialogInterface dialog) {
Log.e("",
"Google Play services resolution cancelled");
mSignInProgress = STATE_DEFAULT;
}
});
} else {
return new AlertDialog.Builder(this)
.setMessage(R.string.play_services_error)
.setPositiveButton(R.string.close,
new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialog,
int which) {
Log.e("",
"Google Play services error could not be "
+ "resolved: "
+ mSignInError);
mSignInProgress = STATE_DEFAULT;
// mStatus.setText(R.string.status_signed_out);
}
}).create();
}
default:
return super.onCreateDialog(id);
}
}
}
I had the same problem. I solved in google api console >> consent screen, and adding a Product Name.
I try this tutorial: http://www.androidhive.info/2014/02/android-login-with-google-plus-account-1/
In the main activity you need change .addApi(Plus.API, null) by .addApi(Plus.API, Plus.PlusOptions.builder().build())
For me the problem was that I had not created the credentials for the app.
Went to Google Developers Console > Credentials > Create New Client ID
filled the corresponding package name and SHA1 for my app, reran the app and then it worked!
In case you are using MapView, make sure you are following the guidelines
i.e.
"When using the API in fully interactive mode, users of this class must forward all the activity life cycle methods to the corresponding methods in the MapView class. Examples of the life cycle methods include onCreate(), onDestroy(), onResume(), and onPause(). When using the API in lite mode, forwarding lifecycle events is optional. For details, see the lite mode documentation."
#Override
public void onResume() {
mapView.onResume();
super.onResume();
}
#Override
public void onDestroy() {
super.onDestroy();
mapView.onDestroy();
}
#Override
public void onLowMemory() {
super.onLowMemory();
mapView.onLowMemory();
}
I am having problem while implementing Google +1 button in my android application.
I followed instruction on this link and my activity is showing g+ button successfully but after clicking on button, it is showing a progress bar on the button only, please tell me how +1 button works in android it should open a login internet or what?
I am not implementing signin with google just +1 button in my app. Hhere is my code, this is part of my code so it is not that proper.
public class as {
private static final String URL = "www.app.in";
private static final int PLUS_ONE_REQUEST_CODE = 10;
private static final int REQUEST_CODE_RESOLVE_ERR = 9000;
private ProgressDialog mConnectionProgressDialog;
private PlusClient mPlusClient;
private ConnectionResult mConnectionResult;
private PlusOneButton mPlusOneButton;
protected void onCreate(Bundle savedInstanceState) {
setContentView(R.layout.product_details);
setCurrentContext(this);
super.onCreate(savedInstanceState);
mPlusOneButton = (PlusOneButton) findViewById(R.id.googleplus);
mPlusClient = new PlusClient.Builder(this, this, this).clearScopes()
.build();
}
#Override
protected void onStart() {
super.onStart();
Log.d(TAG, "OnStart");
mPlusClient.connect();
}
#Override
protected void onStop() {
super.onStop();
Log.d(TAG, "onStop");
mPlusClient.disconnect();
}
#Override
public void onConnectionFailed(ConnectionResult result) {
Log.d(TAG, "onConnectionFailed");
if (mConnectionProgressDialog.isShowing()) {
// The user clicked the sign-in button already. Start to resolve
// connection errors. Wait until onConnected() to dismiss the
// connection dialog.
if (result.hasResolution()) {
try {
result.startResolutionForResult(this,
REQUEST_CODE_RESOLVE_ERR);
} catch (SendIntentException e) {
mPlusClient.connect();
}
}
}
// Save the result and resolve the connection failure upon a user click.
mConnectionResult = result;
}
#Override
protected void onActivityResult(int requestCode, int responseCode,
Intent intent) {
Log.d(TAG, "onActivityResult");
if (requestCode == REQUEST_CODE_RESOLVE_ERR
&& responseCode == RESULT_OK) {
mConnectionResult = null;
mPlusClient.connect();
}
}
#Override
public void onConnected(Bundle connectionHint) {
// String accountName = mPlusClient.getAccountName();
// Toast.makeText(this, accountName + " is connected.",
// Toast.LENGTH_LONG)
// .show();
Log.d(TAG, "onConnected");
}
#Override
public void onDisconnected() {
Log.d(TAG, "disconnected");
}
}
You need to be signed in for this to work, but you do not have to have a sign in button on your app.
If it is enabled (you can click on it) then you are already signed in and I suggest you check that you have specified a valid url.
Your code looks different to mine (I use a GameHelperListener) but as long as you have followed the documentation accurately it should be fine.
If you want to see it work, just download an app that has a +1 button on it, and try it.
Change url like
url="https://market.android.com/details?id=xxx.xxx.xxx";
Also implement methods
ConnectionCallbacks, OnConnectionFailedListener and extends activity