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
Related
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.
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();
}
}
});
}
}
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.
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.
I am going crazy, please help me..
I've following the tutorial page, but without success,
I've added them from android studio
I've enabled the API,
I've got the SHA1 with the default debug keystore
I've created a new client ID and I've created a new key in credential section.
Compile and upload on phone
But nothing seems to work.
I get this stupid error: Connection Result{statusCode=unknown status code 5005, resolution=null}
Stupid and complicated developer console..
Please help me
Today it works. Probably was the wrong packing name.
SOLVED
Just change the package name ..
Here is the api client
private void buildFitnessClient() {
fitnessClient = new GoogleApiClient.Builder(context)
.addApi(Fitness.HISTORY_API)
.addApi(Fitness.SESSIONS_API)
.addScope(new Scope(Scopes.FITNESS_BODY_READ_WRITE))
.addScope(new Scope(Scopes.FITNESS_ACTIVITY_READ_WRITE))
.addScope(new Scope(Scopes.FITNESS_LOCATION_READ_WRITE))
.addScope(new Scope(Scopes.FITNESS_NUTRITION_READ_WRITE))
.addConnectionCallbacks(
new GoogleApiClient.ConnectionCallbacks() {
#Override
public void onConnected(Bundle bundle) {
ReferenceWrapper.getInstance(context)
.setApiClient(fitnessClient);
((OnClientConnectListener) context)
.onclientConnected();
Log.e("Google fit", "connected");
}
#Override
public void onConnectionSuspended(int i) {
}
})
.addOnConnectionFailedListener(
new GoogleApiClient.OnConnectionFailedListener() {
// Called whenever the API client fails to connect.
#Override
public void onConnectionFailed(
ConnectionResult result) {
if (!result.hasResolution()) {
GooglePlayServicesUtil.getErrorDialog(
result.getErrorCode(), context, 0)
.show();
return;
}
if (!authInProgress) {
try {
authInProgress = true;
result.startResolutionForResult(
context,
KeyConstant.REQUEST_OAUTH);
} catch (IntentSender.SendIntentException e) {
}
}
}
}).build();
}