How to download and save in local directory from Google drive selected file in Android programmatically?

sandeepmaaram picture sandeepmaaram · Apr 2, 2017 · Viewed 7.5k times · Source

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.

Answer

Mr.Rebot picture Mr.Rebot · Apr 5, 2017

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.