List files with google drive api (Android) - 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.

Related

Stuck on choose account for application in android

I am using google drive authorization in my application. While I was running the application using android studio debug/run option, it was working fine. But, today I published the application and after installing it, I am stuck at choose account for appname. I don't know what wrong happened?
I tried a few options:
Since the app package name should not contain .example while uploading apk to google play store, I did the same in my https://console.developers.google.com/ credentials. This didn't work.
Tried to re-install the application, but it didn't work either.
the google drive code is:
private void saveFileToDrive() {
// Start by creating a new contents, and setting a callback.
//Log.i(TAG, "Creating new contents.");
Drive.DriveApi.newDriveContents(mGoogleApiClient)
.setResultCallback(new ResultCallback<DriveContentsResult>() {
#Override
public void onResult(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.
FileInputStream fis;
try {
fis = new FileInputStream(outputFile);
ByteArrayOutputStream baos = new ByteArrayOutputStream();
byte[] buf = new byte[1024];
int n;
while (-1 != (n = fis.read(buf)))
baos.write(buf, 0, n);
byte[] photoBytes = baos.toByteArray();
outputStream.write(photoBytes);
outputStream.close();
fis.close();
//Log.w(TAG, "Successfully written: ");
// let us delete the file here
File file = new File(outputFile);
if (file.delete())
{
//Log.d(TAG, "Successfully deleted.");
}
} catch (FileNotFoundException e) {
//Log.w(TAG, "FileNotFoundException: " + e.getMessage());
} catch (IOException e1) {
//Log.w(TAG, "Unable to write file contents." + e1.getMessage());
}
// 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("audio/mpeg").setTitle(file_name_with_extension).build();
// Create an intent for the file chooser, and start it.
Drive.DriveApi.getRootFolder(mGoogleApiClient)
.createFile(mGoogleApiClient, metadataChangeSet, result.getDriveContents())
;
}
});
}
/**
* Called before the activity is destroyed
*/
#Override
public void onDestroy() {
if (mAdView != null) {
mAdView.destroy();
}
super.onDestroy();
}
#Override
protected void onResume() {
super.onResume();
if (mAdView != null) {
mAdView.resume();
}
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();
}
// Connect the client. Once connected, the camera is launched.
mGoogleApiClient.connect();
}
#Override
protected void onPause() {
if (mAdView != null) {
mAdView.pause();
}
if (mGoogleApiClient != null) {
mGoogleApiClient.disconnect();
}
super.onPause();
}
#Override
protected void onActivityResult(final int requestCode, final int resultCode, final Intent data) {
if (resultCode == Activity.RESULT_OK) {
// Store the image data as a bitmap for writing later.
//Log.d(TAG, "Data is saved successfully.");
Toast.makeText(getApplicationContext(), "The file " + file_name + " has been saved successfully to your drive.", Toast.LENGTH_LONG).show();
}
}
#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 (SendIntentException e) {
//Log.e(TAG, "Exception while starting resolution activity", e);
}
}
#Override
public void onConnected(Bundle connectionHint) {
//Log.i(TAG, "API client connected.");
}
#Override
public void onConnectionSuspended(int cause) {
//Log.i(TAG, "GoogleApiClient connection suspended");
}
My app is live here:
https://play.google.com/store/apps/details?id=com.khan.spyrecorder
Please help me to solve the issue.

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.

Download DriveFIle on server

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.

How to replace file in Google Drive?

Using the following code, which is take from android-quickstart, this code can produce multiple files with same name if you take multiple pictures. How can it be modified to ensure the file with the same name is replaced?
public class MainActivity extends Activity implements ConnectionCallbacks,
OnConnectionFailedListener {
private static final String TAG = "android-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.newContents(mGoogleApiClient).setResultCallback(new ResultCallback<ContentsResult>() {
#Override
public void onResult(ContentsResult 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.getContents().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)
.setInitialContents(result.getContents())
.build(mGoogleApiClient);
try {
startIntentSenderForResult(
intentSender, REQUEST_CODE_CREATOR, null, 0, 0, 0);
} catch (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)
.addScope(Drive.SCOPE_FILE)
.addConnectionCallbacks(this)
.addOnConnectionFailedListener(this)
.build();
}
// Connect the client. Once connected, the camera is launched.
mGoogleApiClient.connect();
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mGoogleApiClient = new GoogleApiClient.Builder(this)
.addApi(Drive.API)
.addScope(Drive.SCOPE_FILE)
.addConnectionCallbacks(this)
.addOnConnectionFailedListener(this)
.build();
}
#Override
protected void onStart() {
super.onStart();
mGoogleApiClient.connect();
}
#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.
GooglePlayServicesUtil.getErrorDialog(result.getErrorCode(), 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.
try {
result.startResolutionForResult(this, REQUEST_CODE_RESOLUTION);
} catch (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");
}
}
We can use the Google Drive API to:
- Find the existing file
- Get its ID
- Delete the file
- Write a new file
I open the drive file for writing as follows:
writeDriveFile(DriveFile file, Handler handler){
//see query task below to get a drive file by its name. Be careful you can get multiple data elements in the MetadataBuffer below if you have uploaded multiple files with the same name.
Task<DriveContents> openFileTask = myDriveResourceClient.openFile(file, DriveFile.MODE_WRITE_ONLY);
Then with that task write some object bytes to the stream someObject.getBytes(), no magic here. Then commit the results.
openFileTask
.continueWithTask(task -> {
DriveContents contents = task.getResult();
// Process contents...
try (OutputStream writer = contents.getOutputStream()) {
writer.write(someObject.getBytes());
writer.close();
}
//Add whatever metadata you want here
MetadataChangeSet changeSet = new MetadataChangeSet.Builder()
.setLastViewedByMeDate(new Date())
.build();
//commit the file to Google Drive
Task<Void> commitTask = myDriveResourceClient.commitContents(contents, changeSet);
handler.onWriteResults();
return commitTask;
})
.addOnFailureListener(e -> {
// Handle failure
Log.e(TAG, "Unable to read contents", e);
handler.onDriveError(e);
});
The handler is just an interface I defined for errors or results that I want to process after Drive API execution. You could also add an addOnCompleteListener() to process something once the writing was complete.
file is an instance of DriveFile that can be acquired by a query task. The metadata that come to you in the task code block has a getDriveId() method which has a asDrivefFile() method to get the Drive file you need above.
Query query = new Query.Builder()
.addFilter(Filters.eq(SearchableField.TITLE, "file name"))
.build();
Task<MetadataBuffer> queryTask = mDriveResourceClient.query(query);
Then process the MetadataBuffer
queryTask.continueWithTask(
task -> {
MetadataBuffer metadataBuffer = task.getResult() ;
//I have this loop because I wanted to know if there were other versions of the file on the drive
for(Metadata data : metadataBuffer) {
Log.d(TAG, "******************* metadataBuffer title is " + data.getTitle());
if(data.getTitle().equals("file name")){
//this is just a method I defined that encapsulates the drive writing code above.
writeDriveFile(data.getDriveId().asDriveFile(), jsonContent, handler);
}
}
return task;
})
.addOnCompleteListener(task -> {
//some complete tasks
}
})
.addOnFailureListener(e -> {
Log.e(TAG, "************************** Error searching for " + fileName, e);
handler.onDriveError(e);
});
This code was all for writing to the App folder but you just need to set the right scope when you create you resource client.
Deleting a drive file can be done as follows.
public void deleteDriveFile(DriveResource file){
Task<Void> deleteTask = mDriveResourceClient.delete(file);
deleteTask
.continueWith(task -> {
Log.d(TAG, "************* Deleted drive file: " + file.getDriveId().toInvariantString());
return task;
})
.addOnFailureListener(e -> {
//log some sort of error for yourself
});
}

Categories

Resources