Download DriveFIle on server - android

I have an Android application where my user can select a document to upload and on my server I want to pass the URL that can be used to download the file. I'm basing much of my code on this:
http://www.101apps.co.za/index.php/articles/android-apps-and-google-drive-picking-files.html
and I'm also using these guidelines to download the file:
https://developers.google.com/drive/web/manage-downloads
Problem i'm facing is that the getWebContentLink method is returning null every time. I'm not able to download the file ever on my server (even with the OAuth 2.0 client ID). Is there something i'm missing here?
I'm able to getAlternateLink URL but that is only for viewing the document on a browser, which is not what I want. I have some of my relevant methods below:
public GoogleApiClient getGoogleApiClient() {
if (mGoogleApiClient == null) {
mGoogleApiClient = new GoogleApiClient.Builder(getActivity())
.addApi(Drive.API)
.addScope(Drive.SCOPE_FILE)
.addConnectionCallbacks(this)
.addOnConnectionFailedListener(this)
.build();
}
return mGoogleApiClient;
}
// Google Drive call back
public void onConnected(Bundle bundle) {
if (getGoogleApiClient().isConnected()) {
getDataFromGoogleDrive();
}
}
public void onConnectionSuspended(int i) {
}
public void onConnectionFailed(ConnectionResult connectionResult) {
if (connectionResult.hasResolution()) {
try {
connectionResult.startResolutionForResult(getActivity(), GDRIVE_CONNECTION_REQUEST);
} catch (Exception e) {
AlertUtil.showOkAlert(getActivity(), "Oops", "We were unable to connect to your Google Drive.");
}
} else {
GooglePlayServicesUtil.getErrorDialog(connectionResult.getErrorCode(), getActivity(), 0).show();
}
}
private void getDataFromGoogleDrive() {
try {
IntentSender intentSender = Drive.DriveApi.newOpenFileActivityBuilder().build(getGoogleApiClient());
getActivity().startIntentSenderForResult(intentSender, GDRIVE_FILE_REQUEST, null, 0, 0, 0);
} catch (Exception e) {
Log.w(TAG, "ERROR connecting!", e);
getGoogleApiClient().connect();
}
}
My goal is to allow my user to select a file on the app and then have the server download the file.

I was able to do it this way:
// accountName is the email address that was chosen
token = GoogleAuthUtil.getTokenWithNotification(fragment.getActivity(), accountName, scope, null);
Once you get a token you can make requests as per this page:
https://developers.google.com/drive/web/manage-downloads
The token for Authorization header is above and the resourceId you can get from DriveId.

Related

List files with google drive api (Android)

I'm trying to show the list of files in my google drive, but don't show nothing or only "App data".
This part of code is for to connect with google api , It seems that It's work correctly:
private void connectGoogleDriveApi(){
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.baseActivity)
.addApi(Drive.API)
.addScope(Drive.SCOPE_FILE)
.addScope(Drive.SCOPE_APPFOLDER)
.addConnectionCallbacks(this)
.addOnConnectionFailedListener(this)
.build();
}
// Connect the client. Once connected, the camera is launched.
mGoogleApiClient.connect();
}
#Override
public void onConnected(Bundle bundle) {
Utils.saveInfo("GoogleApiClass", "API client connected.");
try{
//when connect find the files
listAllFiles();
showDriveList();
}catch (Exception e){
Utils.saveError("GoogleApiClass-->onConnected", e.getMessage(), e);
}
}
Then I'm trying recovery the data:
private void listAllFiles() throws Exception{
Utils.saveInfo("GoogleApiClass", "List all files from drive");
String rootFolder= Drive.DriveApi.getRootFolder(this.mGoogleApiClient).getDriveId().toString();
Drive.DriveApi.fetchDriveId(this.mGoogleApiClient, rootFolder)
.setResultCallback(idCallback);
}
final private ResultCallback<DriveApi.DriveIdResult> idCallback = new ResultCallback<DriveApi.DriveIdResult>() {
#Override
public void onResult(DriveApi.DriveIdResult result) {
if (!result.getStatus().isSuccess()) {
Utils.saveInfo("GoogleApiClass-->idCallback","Cannot find DriveId. Are you authorized to view this file?");
return;
}
DriveId driveId = result.getDriveId();
DriveFolder folder = driveId.asDriveFolder();
folder.listChildren(mGoogleApiClient)
.setResultCallback(metadataResult);
}
};
final private ResultCallback<DriveApi.MetadataBufferResult> metadataResult = new
ResultCallback<DriveApi.MetadataBufferResult>() {
#Override
public void onResult(DriveApi.MetadataBufferResult result) {
if (!result.getStatus().isSuccess()) {
Utils.saveInfo("GoogleApiClass-->idCallback","Problem while retrieving files");
return;
}
mResultsAdapter.clear();
mResultsAdapter.append(result.getMetadataBuffer());
Utils.saveInfo("GoogleApiClass-->idCallback","Successfully listed files.");
}
};
Any idea?
Thanks in advance.

Howto get GoogleDrive Quota(remaining available size) with GoogleApiClient?

I use only GoogleApiClient on Android app.
I can not get my GoogleDrive Quota Usage(total/available/etc..).
As Googling..., may be DriveService(com.google.api.services.drive.Drive) is possible... but I am not use that......
How to get GoogleDrive quota info?
(Note) Here is my GoogleApiClient builder.
GDApi = new GoogleApiClient.Builder(mContext)
.addApi(Plus.API)
.addScope(Plus.SCOPE_PLUS_PROFILE)
.addApi(Drive.API)
.addScope(Drive.SCOPE_FILE)
.addConnectionCallbacks(this)
.addOnConnectionFailedListener(this)
.setAccountName(token)
.build();
Unfortunately (AFAIK), there is no equivalent of getQuotaBytesTotal(), getQuotaBytesUsed() in GDAA.
So, the only way to get this info (and other functionalities not present - like thumbnails, ...), is to add the REST Api. Still, be sure you use this mix carefully, you may run into many latency / timing issues.
There are a few pre-requisites for accomplishing this:
1/ make sure you include the following jars in your project:
compile 'com.google.apis:google-api-services-drive:v2-rev105-1.17.0-rc'
compile 'com.google.http-client:google-http-client-gson:1.20.0'
compile 'com.google.api-client:google-api-client-android:1.20.0'
...
import com.google.api.client.extensions.android.http.AndroidHttp;
import com.google.api.client.googleapis.extensions.android.gms.auth.GoogleAccountCredential;
import com.google.api.client.json.gson.GsonFactory;
2/ you will need an additional permission in your manifest:
<uses-permission android:name="android.permission.GET_ACCOUNTS" />
3/ You have to get the com.google.api.services.drive.Drive service and query it after GDAA's onConnected() callback, like so:
private static GoogleApiClient mGAC;
private static com.google.api.services.drive.Drive mGooSvc;
static boolean init(Activity context) {
if (context != null) try {
mGooSvc = new com.google.api.services.drive.Drive.Builder(
AndroidHttp.newCompatibleTransport(),
new GsonFactory(),
GoogleAccountCredential.usingOAuth2(
context.getApplicationContext(),
Collections.singletonList(com.google.api.services.drive.DriveScopes.DRIVE_FILE)
)
).build();
mGAC = new GoogleApiClient.Builder(context)
.addApi(Drive.API)
// ... additional APIs
.addScope(Drive.SCOPE_FILE)
.addConnectionCallbacks(new GoogleApiClient.ConnectionCallbacks() {
#Override
public void onConnectionSuspended(int i) {
}
#Override
public void onConnected(Bundle bundle) {
new Thread(new Runnable() {
#Override
public void run() {
try {
com.google.api.services.drive.model.About about = mGooSvc.about().get().execute();
System.out.println("Total quota (bytes): " + about.getQuotaBytesTotal());
System.out.println("Used quota (bytes): " + about.getQuotaBytesUsed());
} catch (Exception e) { e.printStackTrace(); }
//} catch (UserRecoverableAuthIOException uraIOEx) {
// // standard authorization failure - user fixable
//} catch (GoogleAuthIOException gaIOEx) {
// // usually PackageName /SHA1 mismatch in DevConsole
//} catch (IOException e) {
// if (e instanceof GoogleJsonResponseException) {
// if (404 == ((GoogleJsonResponseException) e).getStatusCode()) {
// // '404 not found' in FILE scope, consider connected
// }
// }
//} catch (Exception e) {
// // "the name must not be empty" indicate
// // UNREGISTERED / EMPTY account in 'setSelectedAccountName()' above
//}
}
}).start();
}
})
.addOnConnectionFailedListener(new GoogleApiClient.OnConnectionFailedListener() {
#Override
public void onConnectionFailed(#NonNull ConnectionResult rslt) {
// perform standard authorization dance
}
})
.build();
mGAC.connect();
return true;
} catch (Exception e) {e.printStackTrace();}
return false;
}
Notice, that I commented out the error / authorization handling for the REST's execute() method. It is because the GDAA's connect()/onConnected()/onConnectionFailed() handles the authorization already (if the scopes are identical).
Good Luck

Multiple instance of GoogleApiClient

Context
When my app is launched for the first time, it asks the user to connect to Google Fit and in the next step (another activity), he has the possibility to connect to Google Plus.
When I accepted to connect to both APIs, once in my app, I have the possibility to disconnect from Fit or Plus, but, I don't know why, it is impossible to disconnect from Fit when the Plus client is connected and if I disconnect from Plus, it works well, but the Fit client gets also disconnected.
When the app is launched, if I decide to connect only to Fit and not Plus, it works as expected, I mean I can disconnect correctly from Fit.
Question
I thought that it was possible to have multiple instances of GoogleApiClient, but I have the impression that both clients are "connected".
Is there a kind of hierarchy between the API clients?
Edit
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main2);
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
/**
* Create the fitness client - this is mandatory to use the app
*/
buildFitnessClient();
/**
* Get the result of Google Plus connection
*/
// If skip button is clicked, the user does not want to connect to G+
Boolean isSkipClicked = getSharedPreferences("ISSKIPCLICKED", MODE_PRIVATE).getBoolean("isSkipClicked", false);
if(isSkipClicked){
// The user has the possibility to connect to G+ through the menu
}
// else, the user is connected to G+, rebuilt the client
else{
buildPlusClient();
mPlusClient.connect();
}
}
The buildFitnessClient() :
private void buildFitnessClient() {
// Create the Google API Client
mClient = new GoogleApiClient.Builder(this)
.addApi(Fitness.HISTORY_API)
.addApi(Fitness.RECORDING_API)
.addApi(Fitness.CONFIG_API)
.addScope(new Scope(Scopes.FITNESS_LOCATION_READ_WRITE))
.addScope(new Scope((Scopes.FITNESS_NUTRITION_READ_WRITE)))
.addScope(new Scope(Scopes.FITNESS_BODY_READ_WRITE))
.addConnectionCallbacks(new GoogleApiClient.ConnectionCallbacks() {
#Override
public void onConnected(Bundle bundle) {
Log.i(TAG, "Connected to Fitness API!!!");
// Now you can make calls to the Fitness APIs.
// Put application specific code here.
mClient.connect();
}
#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(),
Main2Activity.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(Main2Activity.this, REQUEST_OAUTH);
} catch (IntentSender.SendIntentException e) {
Log.e(TAG, "Exception while starting resolution activity", e);
}
}
}
}
)
.build();
}
The buildPlusClient method:
public void buildPlusClient(){
/**
* Handle the connection to Google Plus client
*/
// Configure sign-in to request the user's ID, email address, and basic
// profile. ID and basic profile are included in DEFAULT_SIGN_IN.
GoogleSignInOptions gso = new GoogleSignInOptions.Builder(GoogleSignInOptions.DEFAULT_SIGN_IN)
.requestEmail()
.requestProfile()
.build();
GoogleApiClient.OnConnectionFailedListener unresolvedConnectionFailedListener = new GoogleApiClient.OnConnectionFailedListener() {
#Override
public void onConnectionFailed(ConnectionResult connectionResult) {
Log.d(TAG, "onConnectionFailed:" + connectionResult);
}
};
// Build a GoogleApiClient with access to the Google Sign-In API and the
// options specified by gso.
mPlusClient = new GoogleApiClient.Builder(this)
.enableAutoManage(this /* FragmentActivity */, unresolvedConnectionFailedListener /* OnConnectionFailedListener */)
.addApi(Auth.GOOGLE_SIGN_IN_API, gso)
.build();
}
Below, methods to disconnect from Gplus and/or Gfit:
private void signOutFit(){
if(mClient.isConnected()){
Fitness.ConfigApi.disableFit(mClient)
.setResultCallback(new ResultCallback<Status>() {
#Override
public void onResult(Status status) {
if (status.isSuccess()) {
//Log.d(TAG, "Disconnect success");
Toast.makeText(Main2Activity.this,"Disconnected from Google Fit",Toast.LENGTH_SHORT).show();
} else {
Toast.makeText(Main2Activity.this,"Impossible to disconnect from Fit",Toast.LENGTH_SHORT).show();
}
}
});
}
}
private void signOutPlus(){
if(mPlusClient.isConnected()){
Auth.GoogleSignInApi.signOut(mPlusClient).setResultCallback(
new ResultCallback<Status>() {
#Override
public void onResult(Status status) {
if(status.isSuccess()){
Toast.makeText(Main2Activity.this, "Disconnect from Google Plus", Toast.LENGTH_SHORT).show();
}else{
Toast.makeText(Main2Activity.this, "Impossible to disconnect from Google Plus", Toast.LENGTH_SHORT).show();
}
}
});
}
}

Connection Failed loop with GoogleApiClient

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.

Multiple GoogleApiClient not firing connect()

TL;DR; GoogleFit Api client does not connect if is signed in with Google+
So... I'm facing a problem when using GoogleFit and Google+ api together. I am using Google+ to sign in a user and using GoogleFit to retrieve fitness.
Besides Google+ I have several other login options such as Facebook and Twitter. My problem is that if a user is signed in with Google+ the user can no longer connect to the Google Fit client. Basically when the button to connect to GoogleFit is pressed nothing happens.
IF the user authenticates with Facebook or Twitter the GoogleFit client can connect just fine...
Here are some relevant code from this activity:
Google+ client:
private GoogleApiClient buildGoogleApiClient() {
return new GoogleApiClient.Builder(this)
.addConnectionCallbacks(this)
.addOnConnectionFailedListener(this)
.addApi(Plus.API)
.addScope(Plus.SCOPE_PLUS_LOGIN)
.addScope(Plus.SCOPE_PLUS_PROFILE)
.build();
}
Google Fit client, this method is called whenever the user press the button to link GoogleFit to the app:
public void buildFitnessClient(Button b) {
// Create the Google API Client
fitConnectButton = b;
mClient = new GoogleApiClient.Builder(this)
.addApi(Fitness.API)
.addScope(new Scope(Scopes.FITNESS_ACTIVITY_READ_WRITE))
.addConnectionCallbacks(this)
.addOnConnectionFailedListener(this)
.build();
mClient.connect();
}
Lifecycle stuff:
#Override
public void onConnected(Bundle bundle) {
mSignInClicked = false;
if(mGoogleServices != null) {
Plus.PeopleApi.loadVisible(mGoogleServices, null).setResultCallback(this);
userData = getProfileInformation();
}
if (hasWearDevice) mClient.connect();
}
#Override
protected void onStart() {
super.onStart();
// Connect to G+ api
if(mGoogleServices != null) mGoogleServices.connect();
// Connect to the Fitness API
if (hasWearDevice) mClient.connect();
}
#Override
public void onStop() {
super.onStop();
if(mGoogleServices != null) {
if(mGoogleServices.isConnected()) mGoogleServices.disconnect();
}
if(hasWearDevice) {
if(mClient.isConnected()) mClient.disconnect();
}
}
Any suggestions?
It's not a solution but a suggestion (I can't comment).
Maybe the problem comes from that you can be only be connected with GoogleApiClient only one time.
You are connected with Google+ scope and so when you try to connect with Fit scope it could not work because you are already connected.
Maybe you can use two types of connection :
One with Google Plus only
One with Google Plus AND Google Fit scope.
It could be like this :
mClient = new GoogleApiClient.Builder(this)
.addApi(Plus.API)
.addScope(Plus.SCOPE_PLUS_LOGIN)
.addScope(Plus.SCOPE_PLUS_PROFILE)
.addApi(Fitness.API)
.addScope(new Scope(Scopes.FITNESS_ACTIVITY_READ_WRITE))
.addConnectionCallbacks(this)
.addOnConnectionFailedListener(this)
.build();
Hope it could help....
I ended up solving my problems by using different callback and connectionFailed listeners for each one of the clients.
My builder for the GoogleFitClient ended up looking like this:
public void startFitnessClient() {
mGoogleFitClient = new GoogleApiClient.Builder(this)
.addApi(Fitness.API)
.addScope(new Scope(Scopes.FITNESS_ACTIVITY_READ_WRITE))
.addConnectionCallbacks(new GoogleApiClient.ConnectionCallbacks() {
#Override
public void onConnected(Bundle bundle) {
if (hasWearDevice) mGoogleFitClient.connect();
}
#Override
public void onConnectionSuspended(int i) {
if (i == GoogleApiClient.ConnectionCallbacks.CAUSE_NETWORK_LOST) {
Log.i(LOG_TAG, "Connection lost. Cause: Network Lost.");
} else if (i == GoogleApiClient.ConnectionCallbacks.CAUSE_SERVICE_DISCONNECTED) {
Log.i(LOG_TAG, "Connection lost. Reason: Service Disconnected");
}
}
})
.addOnConnectionFailedListener(new GoogleApiClient.OnConnectionFailedListener() {
#Override
public void onConnectionFailed(ConnectionResult connectionResult) {
// 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(LOG_TAG, "Attempting to resolve failed connection");
authInProgress = true;
connectionResult.startResolutionForResult(BaseActivity.this, REQUEST_OAUTH);
} catch (IntentSender.SendIntentException e) {
Log.e(LOG_TAG, "Exception while starting resolution activity", e);
Crashlytics.logException(e);
}
}
}
})
.build();
}
And this is my client for the Google+ client.
private void buildGoogleApiClient() {
mGooglePlusClient = new GoogleApiClient.Builder(this)
.addConnectionCallbacks(new GoogleApiClient.ConnectionCallbacks() {
#Override
public void onConnected(Bundle bundle) {
mSignInClicked = false;
if(mGooglePlusClient != null) {
Plus.PeopleApi.loadVisible(mGooglePlusClient, null).setResultCallback(BaseActivity.this);
userData = getProfileInformation();
}
}
#Override
public void onConnectionSuspended(int i) {
mGooglePlusClient.connect();
}
})
.addOnConnectionFailedListener(new GoogleApiClient.OnConnectionFailedListener() {
#Override
public void onConnectionFailed(ConnectionResult connectionResult) {
mConnectionResult = connectionResult;
if (!connectionResult.hasResolution()) {
GooglePlayServicesUtil.getErrorDialog(connectionResult.getErrorCode(), BaseActivity.this, 0).show();
return;
}
if (!mIntentInProgress) {
if (mSignInClicked) {
resolveSignInError();
}
}
}
})
.addApi(Plus.API)
.addScope(Plus.SCOPE_PLUS_LOGIN)
.addScope(Plus.SCOPE_PLUS_PROFILE)
.build();
}
For what I observed by Logging every step of the process while debugging is that the authentication intent call happens inside onConnectionFailed with the call to startResolutionForResult and when they were sharing the same callback listeners once the Google+ client was connected that callback was never made by the GoogleFit client. By splitting both of them it's being guarantee that they are being called now.

Categories

Resources