I need my project to do the same thing as the code in Quick Start Google Drive API using the Google Drive API. Instead of an image, I need upload a recorded video with my app. I don't know how to create files, parse the result, or create a byte ArrayList. I tried this good answer but it isn't working.
/**
* Copyright 2013 Google Inc. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
* in compliance with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the
* License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
* express or implied. See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* Android Drive Quickstart activity. This activity takes a photo and saves it
* in Google Drive. The user is prompted with a pre-made dialog which allows
* them to choose the file location.
*/
public class MainActivity extends Activity implements ConnectionCallbacks,
OnConnectionFailedListener {
private static final String TAG = "drive-quickstart";
private static final int CAPTURE_VIDEO_ACTIVITY_REQUEST_CODE = 200;
private static final int REQUEST_CODE_CREATOR = 2;
private static final int REQUEST_CODE_RESOLUTION = 3;
private GoogleApiClient mGoogleApiClient;
private Bitmap mBitmapToSave;
private File file;
/**
* 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;
final File file1 = file;
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.
outputStream = result.getDriveContents()
.getOutputStream();
FileInputStream fis;
try {
fis = new FileInputStream(file.getPath());
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();
outputStream = null;
fis.close();
fis = null;
} catch (FileNotFoundException e) {
Log.w(TAG, "FileNotFoundException: " + e.getMessage());
} catch (IOException e1) {
Log.w(TAG, "Unable to write file contents." + e1.getMessage());
}
/*image.compress(Bitmap.CompressFormat.PNG, 100, bitmapStream);*/
// 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("video/mp4").setTitle("Android Photo.mp4").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 (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
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 CAPTURE_VIDEO_ACTIVITY_REQUEST_CODE:
// Called after a photo has been taken.
if (resultCode == Activity.RESULT_OK) {
// Store the image data as a bitmap for writing later.
Context context = null;
File file = new File(context.getFilesDir(), String.valueOf(REQUEST_CODE_CREATOR));
}
break;
case REQUEST_CODE_CREATOR:
// Called after a file is saved to Drive.
if (resultCode == RESULT_OK) {
Log.i(TAG, "Image successfully saved.");
file = null;
// Just start the camera again for another photo.
startActivityForResult(new Intent(MediaStore.ACTION_VIDEO_CAPTURE),
CAPTURE_VIDEO_ACTIVITY_REQUEST_CODE);
}
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 (SendIntentException e) {
Log.e(TAG, "Exception while starting resolution activity", e);
}
}
#Override
public void onConnected(Bundle connectionHint) {
Log.i(TAG, "API client connected.");
if (file == null) {
// This activity has no UI of its own. Just start the camera.
startActivityForResult(new Intent(MediaStore.ACTION_VIDEO_CAPTURE),
CAPTURE_VIDEO_ACTIVITY_REQUEST_CODE);
return;
}
saveFileToDrive();
}
#Override
public void onConnectionSuspended(int cause) {
Log.i(TAG, "GoogleApiClient connection suspended");
}
}
Related
I am using Google Drive API in my application, I am able to pick(.doc/docx/.pdf in my case) file from google drive, till now everything is fine. But I want to download the selected file and need to send that file to our server by using Multipart. I tried multiple ways, I am getting DriveId and DriveFile but unfortunately I am unable to download download selected file.
I have gone through the Android developer documentation
I am using below code
import android.accounts.Account;
import android.accounts.AccountManager;
import android.app.Activity;
import android.content.Intent;
import android.content.IntentSender;
import android.os.Bundle;
import android.util.Log;
import com.google.android.gms.common.ConnectionResult;
import com.google.android.gms.common.GoogleApiAvailability;
import com.google.android.gms.common.api.GoogleApiClient;
import com.google.android.gms.drive.Drive;
import com.google.android.gms.drive.DriveFile;
import com.google.android.gms.drive.DriveId;
import com.google.android.gms.drive.DriveResource;
import com.google.android.gms.drive.OpenFileActivityBuilder;
import com.google.api.client.extensions.android.http.AndroidHttp;
import com.google.api.client.http.HttpTransport;
import com.google.api.client.json.JsonFactory;
import com.google.api.client.json.gson.GsonFactory;
import com.google.api.services.drive.DriveScopes;
public class DriveActivity extends Activity implements GoogleApiClient.ConnectionCallbacks,
GoogleApiClient.OnConnectionFailedListener {
/**
* DriveId of an existing folder to be used as a parent folder in
* folder operations samples.
*/
public static final String EXISTING_FOLDER_ID = "0B2EEtIjPUdX6MERsWlYxN3J6RU0";
/**
* DriveId of an existing file to be used in file operation samples..
*/
public static final String EXISTING_FILE_ID = "0ByfSjdPVs9MZTHBmMVdSeWxaNTg";
/**
* Extra for account name.
*/
protected static final String EXTRA_ACCOUNT_NAME = "account_name";
/**
* Request code for auto Google Play Services error resolution.
*/
protected static final int REQUEST_CODE_RESOLUTION = 1;
/**
* Next available request code.
*/
protected static final int NEXT_AVAILABLE_REQUEST_CODE = 2;
private static final String TAG = "===GoogleDriveActivity";
private static final int REQUEST_CODE_OPENER = 2;
/**
* Google API client.
*/
private GoogleApiClient mGoogleApiClient;
private static final String[] SCOPES = {DriveScopes.DRIVE_FILE};
final HttpTransport transport = AndroidHttp.newCompatibleTransport();
final JsonFactory jsonFactory = GsonFactory.getDefaultInstance();
private String accountName;
DriveResource.MetadataResult metadataResult;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
connect();
}
#Override
protected void onStop() {
if (mGoogleApiClient != null) {
mGoogleApiClient.disconnect();
}
super.onStop();
}
#Override
protected void onRestart() {
super.onRestart();
connect();
}
private void connect() {
if (mGoogleApiClient == null) {
mGoogleApiClient = new GoogleApiClient.Builder(this)
.addApi(Drive.API)
.addScope(Drive.SCOPE_FILE)
.addScope(Drive.SCOPE_APPFOLDER) // required for App Folder sample
.addConnectionCallbacks(this)
.addOnConnectionFailedListener(this)
.build();
}
mGoogleApiClient.connect();
}
/**
* Called when {#code mGoogleApiClient} is disconnected.
*/
#Override
public void onConnectionSuspended(int cause) {
Log.i(TAG, "GoogleApiClient connection suspended");
}
/**
* Called when {#code mGoogleApiClient} is trying to connect but failed.
* Handle {#code result.getResolution()} if there is a resolution is
* available.
*/
#Override
public void onConnectionFailed(ConnectionResult result) {
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;
}
try {
result.startResolutionForResult(this, REQUEST_CODE_RESOLUTION);
} catch (IntentSender.SendIntentException e) {
Log.e(TAG, "Exception while starting resolution activity", e);
}
}
/**
* Getter for the {#code GoogleApiClient}.
*/
public GoogleApiClient getGoogleApiClient() {
return mGoogleApiClient;
}
#Override
public void onConnected(Bundle connectionHint) {
IntentSender intentSender = Drive.DriveApi
.newOpenFileActivityBuilder()
.setMimeType(new String[]{"application/msword", " application/vnd.openxmlformats-officedocument.wordprocessingml.document", "application/vnd.google-apps.document", "application/pdf"})
.build(getGoogleApiClient());
AccountManager manager = (AccountManager) getSystemService(ACCOUNT_SERVICE);
Account[] list = manager.getAccountsByType("com.google");
//Getting the first account because that is the primary account for that user
accountName = list[0].name;
try {
startIntentSenderForResult(
intentSender, REQUEST_CODE_OPENER, null, 0, 0, 0);
} catch (IntentSender.SendIntentException e) {
Log.w(TAG, "Unable to send intent", e);
}
}
/**
* Handles resolution callbacks.
*/
#Override
protected void onActivityResult(int requestCode, int resultCode,
Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (resultCode == RESULT_OK) {
switch (requestCode) {
case REQUEST_CODE_OPENER:
Intent intent = null;
if (resultCode == RESULT_OK) {
DriveId driveId = data.getParcelableExtra(
OpenFileActivityBuilder.EXTRA_RESPONSE_DRIVE_ID);
String resourceId = driveId.getResourceId();
DriveFile file = driveId.asDriveFile();
}
break;
case REQUEST_CODE_RESOLUTION:
mGoogleApiClient.connect();
break;
default:
super.onActivityResult(requestCode, resultCode, data);
}
}
}
}
Please can someone help me to download selected file from google drive programmatically?
Thanks in advance.
There are two ways you can download it, via REST or using GDAA. You can use either depending on where you code comfortably.
When using REST:
/*************************************************************************
* get file contents
* #param resId file driveId
* #return file's content / null on fail
*/
static InputStream read(String resId) {
if (mGOOSvc != null && mConnected && resId != null) try {
File gFl = mGOOSvc.files().get(resId).setFields("downloadUrl").execute();
if (gFl != null){
String strUrl = gFl.getDownloadUrl();
return mGOOSvc.getRequestFactory()
.buildGetRequest(new GenericUrl(strUrl)).execute().getContent();
}
} catch (Exception e) { /* error handling */ }
return null;
}
WHEN using GDAA:
/************************************************************************************************
* get file contents
* #param id file driveId
* #return file's content / null on fail
*/
static byte[] read(String id) {
byte[] buf = null;
if (mGAC != null && mGAC.isConnected() && id != null) try {
DriveFile df = Drive.DriveApi.getFile(mGAC, DriveId.decodeFromString(id));
DriveContentsResult rslt = df.open(mGAC, DriveFile.MODE_READ_ONLY, null).await();
if ((rslt != null) && rslt.getStatus().isSuccess()) {
DriveContents cont = rslt.getDriveContents();
buf = UT.is2Bytes(cont.getInputStream());
cont.discard(mGAC); // or cont.commit(); they are equiv if READONLY
}
} catch (Exception e) { UT.le(e); }
return buf;
}
Check this SO post for the differentiation of Drive Rest in GDAA.
1 The GDAA's main identifier, the DriveId lives in GDAA (GooPlaySvcs) only and does not exist in the REST Api. You must retrieve 'ResourceId' which is the main identifier in the REST Api (see SO 29030110).
2 ResourceId can be obtained from the DriveId only after GDAA committed (uploaded) the file/folder (see SO 22874657)
3 You will run into a lot of timing issues caused by the fact that GDAA 'buffers' network requests on it's own schedule (system optimized), whereas the REST Api let your app control the waiting for the response. In general, if you scan these SO questions, you'll find a lot of chatter about these issues (it's a mess, though).
Hope this helps.
Just Pass DriveID of Upload File And Filename you want to give while download
public void DownloadFile(final DriveId driveId, final File filename, final GoogleApiClient mGoogleApiClient) {
if (!filename.exists()) {
try {
filename.createNewFile();
} catch (IOException e) {
e.printStackTrace();
}
}
final DriveFile file = Drive.DriveApi.getFile(mGoogleApiClient, driveId);
file.getMetadata(mGoogleApiClient).setResultCallback(metadataRetrievedCallback);
DriveFolder folder = Drive.DriveApi.getFolder(mGoogleApiClient, driveId);
folder.getMetadata(mGoogleApiClient).setResultCallback(metadataRetrievedCallback1);
new Thread(new Runnable()
{
#Override
public void run()
{
DriveApi.DriveContentsResult driveContentsResult = file.open(mGoogleApiClient,DriveFile.MODE_READ_ONLY, null).await();
DriveContents driveContents = driveContentsResult.getDriveContents();
InputStream inputstream = driveContents.getInputStream();
try
{
FileOutputStream fileOutput = new FileOutputStream(filename);
byte[] buffer = new byte[1024];
int bufferLength = 0;
while ((bufferLength = inputstream.read(buffer)) > 0)
{
fileOutput.write(buffer, 0, bufferLength);
}
fileOutput.close();
inputstream.close();
}
catch (IOException e) {
e.printStackTrace();
}
}
}).start();
}
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.
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.
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
});
}
My app can save an image to Google Drive (like https://github.com/googledrive/android-quickstart). How can I get the URL of the uploaded image and save it in a variable, for showing it to the user in textview, and save it into an SQLite database?
public class Phototodrive 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>() {
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("Doc_scan.jpg").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
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 i) {
Log.i(TAG, "GoogleApiClient connection suspended");
}
final private ResultCallback<DriveFileResult> fileCallback = new ResultCallback<DriveFileResult>(){
#Override
public void onResult(DriveFileResult result) {
if (!result.getStatus().isSuccess()){
//showMessage("Error");
Toast.makeText(getApplicationContext(), "Error",
Toast.LENGTH_LONG).show();
return;
}
// showMessage("Created a file: " + result.getDriveFile().getDriveId());
Toast.makeText(getApplicationContext(), "Created a file: " + result.getDriveFile().getDriveId(),
Toast.LENGTH_LONG).show();
}
};
}
There is an ID called Resource ID you get from DriveId.getResourceId(), see SO 21800257 that allows you to form URL of the file, something that looks like
https://docs.google.com/file/d/0B1mQU..........ZRTc5SHRlNjg/
The rest of your question should be easy to answer. It is a string so it can be saved, shown,... as such. But make sure that you form the URL string correctly. The example above is just one specific to my app. The key is still the Resource ID.
I used another method to upload a new photo to Google drive, because I also needed to OCR it. Now I can get the Id of the file easily.
//upload the file and OCR it
File file = service.files().insert(body, mediaContent).setOcr(true).execute();
//save the id into a string
String fileid=file.getId();