0

Hi I want to develop an app that takes photo and uploads to Google Drive. I found the master(source code) from Github today which is by Google https://github.com/googledrive/android-quickstart

This is very useful. But I found some problems that If i Press back button the application still does not finish it's activity. By default it always opens camera and taking photo and saving it to the Google Drive.Its doing the same thing again and again.If I want to exit the app I cannot until I press Home button. Any solution? Also There is another problem: after taking photo it shows a dialog windows asking where to save the image and what will be the image name.The problem is if I press cancel button it shows the same dialog again and again. If I press Ok then it doesnot show the dialog but If I press cancel it shows the same dialog again. I want to get rid of it when I press cancel. Any solution? This is the code :

package com.randb.uploadtogdrive;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.OutputStream;

import android.app.Activity;
import android.content.Intent;
import android.content.IntentSender;
import android.content.IntentSender.SendIntentException;
import android.graphics.Bitmap;
import android.os.Bundle;
import android.provider.MediaStore;
import android.util.Log;
import android.widget.Toast;

import com.google.android.gms.common.ConnectionResult;
import com.google.android.gms.common.GooglePlayServicesUtil;
import com.google.android.gms.common.api.GoogleApiClient;
import com.google.android.gms.common.api.GoogleApiClient.ConnectionCallbacks;
import com.google.android.gms.common.api.GoogleApiClient.OnConnectionFailedListener;
import com.google.android.gms.common.api.ResultCallback;
import com.google.android.gms.drive.Drive;
import com.google.android.gms.drive.DriveApi.ContentsResult;
import com.google.android.gms.drive.MetadataChangeSet;
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("myPhoto.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
protected void onPause() {
    if (mGoogleApiClient != null) {
        mGoogleApiClient.disconnect();
    }
    super.onPause();
}
@Override
public void onBackPressed(){
    Toast.makeText(MainActivity.this,"Going Somehwere?", Toast.LENGTH_LONG).show();
    finish();
}
@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");
}
Anish Ubais
  • 33
  • 2
  • 12

2 Answers2

0

Here is a quick fix for your problem. Back button from both the activities you're talking about (camera, creator) returns 'Activity.RESULT_CANCELED', so just kill your activity (using finish()) when you don't get 'Activity.RESULT_OK'.

  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");
      } else 
        finish();
      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);
      } else 
        finish();
      break;
  }

But in general, 'quickstart' is usually just a proof-of-concept, not something you should build you app on.

seanpj
  • 6,735
  • 2
  • 33
  • 54
  • thank you that works!!.I have another doubt.Currently the uploaded image is having a small size.probably because the code contains image compression(image.compress(Bitmap.CompressFormat.PNG, 100, bitmapStream);).So can u show me how the save the image with its original size,without using compression? – Anish Ubais Jul 11 '14 at 01:22
  • The answer is here: http://developer.android.com/training/camera/photobasics.html – seanpj Jul 11 '14 at 03:02
  • The get("data") gives you only a thumbnail. If you need full size, you have to create a file, pass it to the camera activity and then grab it, it has image in it. I'll stick some code to another answer below – seanpj Jul 11 '14 at 03:10
0

This should take care of you 'thumbnail' problem. Basically, replace the bitmap mBitmapToSave with a file '_picFl'. The code below is modified, the var names are different, but it does essentially what you're asking for.

private File            _picFl;
private GoogleApiClient _gac;

@Override public void onConnected(Bundle connectionHint) {
    if (_picFl == null)
      takePic();
    else 
      save2GooDrv();
  }
  //-----------------------------------------------------------------------------------------------
  private void takePic() {
    Intent icIt = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
    if (icIt.resolveActivity(getPackageManager()) != null) try {
      _picFl =  new File(getCcheDir(), tm2FlNm(null));
      if (_picFl != null) {
        icIt.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(_picFl));
        startActivityForResult(icIt, RC_GETIMAGE);
      }
    } catch (Exception e) {le(e);}
  }
  //-----------------------------------------------------------------------------------------------
  private synchronized void save2GooDrv() {
    Drive.DriveApi.newContents(_gac).setResultCallback(new ResultCallback<ContentsResult>() {
      @Override public void onResult(ContentsResult rslt) {
        if (rslt.getStatus().isSuccess()) try {
          OutputStream os = rslt.getContents().getOutputStream();
          os.write(file2Bytes(_picFl));
          MetadataChangeSet metadataChangeSet = new MetadataChangeSet.Builder()
                                   .setMimeType("image/jpeg").setTitle(_picFl.getName()).build();
          _picFl.delete();
          _picFl = null;

          IntentSender intentSender = Drive.DriveApi
              .newCreateFileActivityBuilder()
              .setInitialMetadata(metadataChangeSet)
              .setInitialContents(rslt.getContents())
              .build(_gac);
          try {
            startIntentSenderForResult( intentSender, RC_CREATOR, null, 0, 0, 0);
          } catch (SendIntentException e) {le(e);}
        } catch (Exception e) {le(e);}
      }
    });
  }

  //***********************************************************************************************
  public String getCcheDir() {
    Context actx = getApplicationContext();

    return Environment.MEDIA_MOUNTED.equals(Environment.getExternalStorageState()) ||
                                                      !Environment.isExternalStorageRemovable() ?
     actx.getExternalCacheDir().getPath() : actx.getCacheDir().getPath();
  }

  //***********************************************************************************************
  public byte[] file2Bytes(File file) {
    byte[] buf = null;
    RandomAccessFile raFl = null;
    if (file != null) try {
      raFl = new RandomAccessFile(file, "r");
      buf = new byte[(int)raFl.length()];
      raFl.readFully(buf);
    } catch (Exception e) {le(e);}
    finally { 
       if (raFl != null) try { 
         raFl.close();
       } catch (Exception e) {le(e);}
     }
    return buf;
  }

  //***********************************************************************************************
  public String tm2FlNm(Long milis) {       // time -> yymmdd-hhmmss
    try {
      return  new SimpleDateFormat("yyMMdd-HHmmss",Locale.US)
                                          .format((milis == null) ? new Date() : new Date(milis));
    } catch (Exception e) {le(e);}
    return null;
  }  

  //***********************************************************************************************
  public void le(Exception e){
    try { 
      Log.e("_", (e==null) ? "NULL" : Log.getStackTraceString(e));
    }catch (Exception f) { try { Log.e("_", "ERR on err");}  catch (Exception g) {} }
  }
seanpj
  • 6,735
  • 2
  • 33
  • 54
  • Thank you seanpj.That code worked..I want to upload the images to a folder created from my app each time.so each time app has to check whether there is a folder with a specific name.if the folder found then upload otherwise create a folder and upload.I tried my own code but due synchronize issue i cannot achieve the required result.Any solution please? – Anish Ubais Jul 19 '14 at 06:42
  • I've been skating on this thin ice for a few months now. My original idea was: 1/ update config file in the app folder, use requestSync() 2/ get notification on other devices (with the same app) via 'DriveEvent.Listener' Doesn't work. You get the notification 'sometime when GOOPlaySvcs decide' You are better off by polling the Drive. And you have to do it using the 'old' RESTful API. – seanpj Jul 19 '14 at 12:18
  • Using REST and GDAA leads to full bunch of timing issues, since GDAA is caching and managing communication with Drive asynchronously. ON top of it, GDAA supports FILE scope only, does not have DELETE, doesn't give you thumbnail link, does not support full-text search. Most of these things were promised half a year ago and never delivered. There is a ton of questions on SA (22515028,22874657,23073474,24562387,23711686,23626827) – seanpj Jul 19 '14 at 12:19