1

I want to download file from google drive for which I am using dependency that is compile 'com.google.android.gms:play-services:8.4.0' and using this I am able to get link from meta data from below example.

mFileId = (DriveId) data.getParcelableExtra(
                        OpenFileActivityBuilder.EXTRA_RESPONSE_DRIVE_ID);


                final DriveFile file = Drive.DriveApi.getFile(mGoogleApiClient, mFileId);


                new Thread(new Runnable() {
                    @Override
                    public void run() {
                        // DO your work here
                        DriveResource.MetadataResult mdRslt = file.getMetadata(mGoogleApiClient).await();
                        if (mdRslt != null && mdRslt.getStatus().isSuccess()) {
                           String  link = mdRslt.getMetadata().getWebContentLink();
                            String name=mdRslt.getMetadata().getTitle();
                            Log.d("LINK", link);
                            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && getApplication().checkSelfPermission(Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED)
                            {
                                requestPermissions(new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, 1);
                            }
                            else
                            {

                              new  get_download_data(link,name).execute();
                            }
                        }
                    }
                }).start();
                }

After getting the link from Google Drive, I am calling async task to download that file from link. So my problem is when I am downloading file, it's not opening. After checking and debugging, I found that my files was not downloading properly.

For example, I have file name abc.pdf and the size is 400kb. I downloaded on my sdcard but abc.pdf is 56 kb only. I am using below code for downloading. I don't know where I was doing wrong. Please help. Thanks.

 public class get_download_data extends AsyncTask<Void,Void,String>
{
    File apkStorage = null;
    File outputFile = null;
    String link1="";
    String name1="";

    public get_database_data(String link, String name) {
        this.link1=link;
        this.name1=name;
    }
    protected void onPreExecute() {
        super.onPreExecute();



    }
    @Override
    protected String doInBackground(Void... params) {

        try {

            URL url = new URL(link1);//Create Download URl

            HttpURLConnection c = (HttpURLConnection) url.openConnection();//Open Url Connection
            c.setRequestMethod("GET");//Set Request Method to "GET" since we are grtting data


            c.setDoInput(true);

            c.connect();//connect the URL Connection

            //If Connection response is not OK then show Logs
            if (c.getResponseCode() != HttpURLConnection.HTTP_OK) {
                Log.e(TAG, "Server returned HTTP " + c.getResponseCode()
                        + " " + c.getResponseMessage());

            }else{
                Log.e(TAG, "Server returned HTTP " + c.getResponseCode()
                        + " " + c.getResponseMessage());
            }


            //Get File if SD card is present
            if (new CheckForSDCard().isSDCardPresent()) {

                apkStorage = new File(
                        Environment.getExternalStorageDirectory() + "/"
                                + "checkdb");
            } else
                Toast.makeText(getApplication(), "Oops!! There is no SD Card.", Toast.LENGTH_SHORT).show();

            //If File is not present create directory
            if (!apkStorage.exists()) {
                apkStorage.mkdir();
                Log.e(TAG, "Directory Created.");
            }

            outputFile = new File(apkStorage, name1);//Create Output file in Main File

            //Create New File if not present
            if (!outputFile.exists()) {
                outputFile.createNewFile();
                Log.e(TAG, "File Created");
            }

            OutputStream fos = new FileOutputStream(outputFile);//Get OutputStream for NewFile Location

            InputStream is = c.getInputStream();//Get InputStream for connection
            BufferedInputStream inStream = new BufferedInputStream(is, 1024);

            byte[] buffer = new byte[1024];//Set buffer type
            int len1 = 0;//init length
            while ((len1 = inStream.read(buffer)) != -1) {
                fos.write(buffer, 0, len1);//Write new file
            }

            //Close all connection after doing task
            fos.flush();
            fos.close();
            is.close();

        } catch (Exception e) {

            //Read exception if something went wrong
            e.printStackTrace();
            outputFile = null;
            Log.e(TAG, "Download Error Exception " + e.getMessage());
        }
        return null;
    }

    @Override
    protected void onPostExecute(String result_1) {
        super.onPostExecute(result_1);
        String downlodepath = Environment.getExternalStorageState()+"/"+name1;
        Log.e("Sdpath",""+imagePath);
        Toast.makeText(getApplication(), "download"+downlodepath, Toast.LENGTH_SHORT).show();

    }
}

I found this link here but some how I don't have idea how to implement this. Please let me know where I was wrong. Thanks.

abielita
  • 12,126
  • 2
  • 15
  • 52
umesh vashisth
  • 321
  • 2
  • 16

4 Answers4

5

After some work around and trying so many examples, I found the answer for this. Here are the dependencies which I have added in my project:

compile 'com.google.android.gms:play-services-auth:11.8.0'
compile 'com.google.android.gms:play-services-drive:11.8.0'

Here is my manifest file:

<?xml version="1.0" encoding="utf-8"?>
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />

<application
    android:allowBackup="false"
    android:icon="@mipmap/ic_launcher"
    android:label="@string/app_name"
    android:roundIcon="@mipmap/ic_launcher_round"
    android:supportsRtl="true"
    android:theme="@style/AppTheme">

    <activity android:name=".MainActivity">
        <intent-filter>
            <action android:name="android.intent.action.MAIN" />

            <category android:name="android.intent.category.LAUNCHER" />
        </intent-filter>
    </activity>

    <meta-data
        android:name="com.google.android.geo.API_KEY"
        android:value="@string/google_api_key" />

    <meta-data
        android:name="com.google.android.gms.version"
        android:value="@integer/google_play_services_version" />
</application>

</manifest>

Here is my MainActivity:

public class MainActivity extends AppCompatActivity implements View.OnClickListener {

private ActivityMainBinding binding;

private static final String TAG = "Google drive";
private static final String SIGN_IN = "Sign In";
private static final String DOWNLOAD_FILE = "Download file";

private static final int REQUEST_CODE_SIGN_IN = 0;
private static final int REQUEST_CODE_OPEN_ITEM = 1;
private static final int REQUEST_WRITE_STORAGE = 112;


private GoogleSignInAccount signInAccount;
private Set<Scope> requiredScopes;
private DriveClient mDriveClient;
private DriveResourceClient mDriveResourceClient;

private OpenFileActivityOptions openOptions;
private TaskCompletionSource<DriveId> mOpenItemTaskSource;
private File storageDir;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    binding = DataBindingUtil.setContentView(this, R.layout.activity_main);

    initialize();
    requestPermission();
    signInAccount = GoogleSignIn.getLastSignedInAccount(this);

    binding.btnSubmit.setOnClickListener(this);
    if (signInAccount != null && signInAccount.getGrantedScopes().containsAll(requiredScopes)) {
        initializeDriveClient(signInAccount);
        binding.btnSubmit.setText(DOWNLOAD_FILE);
    } else {
        binding.btnSubmit.setText(SIGN_IN);
    }

}

private void showMessage(String message) {
    Toast.makeText(this, message, Toast.LENGTH_LONG).show();
}

@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
    super.onActivityResult(requestCode, resultCode, data);
    switch (requestCode) {
        case REQUEST_CODE_SIGN_IN:
            if (resultCode == RESULT_OK) {
                Task<GoogleSignInAccount> getAccountTask = GoogleSignIn.getSignedInAccountFromIntent(data);
                if (getAccountTask.isSuccessful()) {
                    initializeDriveClient(getAccountTask.getResult());
                    showMessage("Sign in successfully.");
                    binding.btnSubmit.setText(DOWNLOAD_FILE);
                } else {
                    showMessage("Sign in failed.");
                }
            } else {
                showMessage("Sign in failed.");
            }
            break;
        case REQUEST_CODE_OPEN_ITEM:
            if (resultCode == RESULT_OK) {
                DriveId driveId = data.getParcelableExtra(OpenFileActivityOptions.EXTRA_RESPONSE_DRIVE_ID);
                mOpenItemTaskSource.setResult(driveId);
            } else {
                mOpenItemTaskSource.setException(new RuntimeException("Unable to open file"));
            }
            break;
    }
}


private void initialize() {

    requiredScopes = new HashSet<>(2);
    requiredScopes.add(Drive.SCOPE_FILE);
    requiredScopes.add(Drive.SCOPE_APPFOLDER);

    openOptions = new OpenFileActivityOptions.Builder()
            .setSelectionFilter(Filters.eq(SearchableField.MIME_TYPE, "application/pdf"))
            .setActivityTitle("Select file")
            .build();
}

private void initializeDriveClient(GoogleSignInAccount signInAccount) {
    mDriveClient = Drive.getDriveClient(getApplicationContext(), signInAccount);
    mDriveResourceClient = Drive.getDriveResourceClient(getApplicationContext(), signInAccount);
}

@Override
public void onClick(View view) {
    if (view.getId() == R.id.btnSubmit) {
        String text = (String) ((Button) view).getText();
        if (text.equals(SIGN_IN)) {
            signIn();
        } else {
            onDriveClientReady();
        }
    }
}

private void signIn() {
    GoogleSignInOptions signInOptions = new GoogleSignInOptions.Builder(GoogleSignInOptions.DEFAULT_SIGN_IN)
            .requestScopes(Drive.SCOPE_FILE)
            .requestScopes(Drive.SCOPE_APPFOLDER)
            .build();
    GoogleSignInClient googleSignInClient = GoogleSignIn.getClient(this, signInOptions);
    startActivityForResult(googleSignInClient.getSignInIntent(), REQUEST_CODE_SIGN_IN);
}

private void onDriveClientReady() {
    mOpenItemTaskSource = new TaskCompletionSource<>();
    mDriveClient.newOpenFileActivityIntentSender(openOptions)
            .continueWith(new Continuation<IntentSender, Void>() {
                @Override
                public Void then(@NonNull Task<IntentSender> task) throws Exception {
                    startIntentSenderForResult(
                            task.getResult(), REQUEST_CODE_OPEN_ITEM, null, 0, 0, 0);
                    return null;
                }
            });

    Task<DriveId> tasks = mOpenItemTaskSource.getTask();
    tasks.addOnSuccessListener(this,
            new OnSuccessListener<DriveId>() {
                @Override
                public void onSuccess(DriveId driveId) {
                    retrieveContents(driveId.asDriveFile());
                }
            })
            .addOnFailureListener(this, new OnFailureListener() {
                @Override
                public void onFailure(@NonNull Exception e) {
                    showMessage("File not selected.");
                }
            });
}

private void retrieveContents(final DriveFile file) {
    // [START open_file]
    final Task<DriveContents> openFileTask = mDriveResourceClient.openFile(file, DriveFile.MODE_READ_ONLY);
    // [END open_file]
    // [START read_contents]
    openFileTask.continueWithTask(new Continuation<DriveContents, Task<Void>>() {
        @Override
        public Task<Void> then(@NonNull Task<DriveContents> task) throws Exception {
            DriveContents contents = task.getResult();

            Log.v(TAG, "File name : " + contents.toString());
            if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.KITKAT) {
                InputStream input = contents.getInputStream();

                try {
                    File file = new File(getExternalFilesDir(null), "umesh.pdf");
                    Log.v(TAG, storageDir + "");
                    OutputStream output = new FileOutputStream(file);
                    try {
                        try {
                            byte[] buffer = new byte[4 * 1024]; // or other buffer size
                            int read;

                            while ((read = input.read(buffer)) != -1) {
                                output.write(buffer, 0, read);
                            }
                            output.flush();
                        } finally {
                            output.close();
                        }
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                } catch (FileNotFoundException e) {
                    e.printStackTrace();
                } finally {
                    try {
                        input.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            }
            showMessage("Download file successfully.");
            return mDriveResourceClient.discardContents(contents);
        }
    })
            .addOnFailureListener(new OnFailureListener() {
                @Override
                public void onFailure(@NonNull Exception e) {
                    showMessage("Unable to download file.");
                }
            });
    // [END read_contents]
}

private void requestPermission() {
    String dirPath = getFilesDir().getAbsolutePath() + File.separator + "PDF";
    storageDir = new File(dirPath);
    if (!storageDir.exists())
        storageDir.mkdirs();}}

And here is the string file for the API key:

<resources>
    <string name="app_name">GoogleDriveDemo</string>

    <string name="google_api_key">"your-key"</string>
</resources>
Pang
  • 8,605
  • 144
  • 77
  • 113
umesh vashisth
  • 321
  • 2
  • 16
  • I tried downloading Google Doc and spreadsheet via this code but I am unable to download. Do you have any idea? how to download Google Doc, Spreadsheet and Presentation? – Maroti Mar 16 '18 at 13:58
  • @shailesh did you changed MIME_TYPE in code??...and please check for this code its only down lode pdf files. – umesh vashisth Mar 19 '18 at 06:35
  • Hi Umesh thanks for the reply, I am aware of it and also I am successfully done for .docx, .doc, .ppt, and .txt files. Even used proper MIME_TYPE for Google Doc, Spreadsheet, and Presentation and after that, it's showing me all type of doc in the list but the problem for downloading this doc. No problem I got the solution for it. – Maroti Mar 20 '18 at 06:01
  • @Shailesh its good to hear that u find the solution.happy coding. – umesh vashisth Mar 20 '18 at 08:55
  • @umeshvashisth Do you need to create credentials to get your code working? Also, would you be willing to help me overcome the same problems you had when you managed to get the Drive API working? Thank you in advance. – ChrisUK Jul 08 '19 at 11:27
  • @ChrisUK what kind of problems you are facing can you describe me ???.....however if you just follow my ans you will be able to use drive just use your own google_api_key. – umesh vashisth Jul 08 '19 at 13:23
  • @umeshvashisth I'm getting a "Sign in failed" error, but it might be an issue with my API key. How did you get your API Key and where did you put it in your Android project? Thanks :-) – ChrisUK Jul 08 '19 at 13:41
  • @umeshvashisth I suppose what I'm asking is do I need to download a credentials.json file and put it in a project folder - and is it a basic credential or the complicated version that involves SHA-1 fingerprints? Sorry about this but I'm very much a beginner with this sort of thing and I really appreciate your reply. – ChrisUK Jul 08 '19 at 14:10
  • @ChrisUK i dont think you have to add .json file into your project.the only thing u need to add is your google_api_key and your app_key which you will get from your google developer account.after you get the key simply add that into resource string file.i hope you get my point. – umesh vashisth Jul 09 '19 at 06:00
  • @umeshvashisth Thanks for your reply. I have an API Key that I've added as a resource string, but what is the "app_key"? – ChrisUK Jul 09 '19 at 09:18
  • @ChrisUK its Generated access token which you will get from [https://www.dropbox.com/developers/apps] here.open your project and you can see there is a App key which you have to use. – umesh vashisth Jul 09 '19 at 13:24
0

The way I use webContentLink when downloading a file in Drive API is to open a new browser window in Javascript.

var webcontentlink = 'https://docs.google.com/a/google.com/uc?id='+fileId+'&export=download'
window.open( webcontentlink);

I'd suggest you do that in Android like the one mentioned in this post:

Intent browserIntent = new Intent(Intent.ACTION_VIEW, Uri.parse(webcontentlink));
startActivity(browserIntent);
noogui
  • 15,376
  • 3
  • 18
  • 42
0

For someone who still stuck in this problem. Somehow the download URL cannot be returned right after driveResourceClient.createFile()

driveResourceClient?.createFile(appFolder, metadataChangeSet, contents)
            }?.addOnSuccessListener(this
            ) { driverFile -> //we cannot get webContentLink here }

At this time we can only get the file name (this one may already defined)

In my case, I don't really need the URL right after upload but when user click a copy URL button

driveResourceClient?.query(Query.Builder()
                .addFilter(Filters.eq(SearchableField.TITLE, sharedFileName))
                .build())
                ?.addOnSuccessListener {
                    url = it.first().webContentLink
                }
                ?.{
                }

I've just success with this.

Ven
  • 1
0

You can easily do that using chrome custom tabs just paste the url in the custom tabs and it will show the drive website and one can download the file Refer this official documentation for chrome custom tabs https://developer.chrome.com/multidevice/android/customtabs it's an really superb feature and a best alternative for webview

TECH SMASH
  • 105
  • 5