Skip to content

Commit

Permalink
Merge pull request #13 from cmsc436/drive
Browse files Browse the repository at this point in the history
Add support for image uploads to Drive (fixes #4)
  • Loading branch information
MrPickles authored Apr 17, 2017
2 parents 0b41b42 + 9bfb059 commit 67da2be
Show file tree
Hide file tree
Showing 9 changed files with 235 additions and 13 deletions.
39 changes: 37 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,16 @@ you will not need to download any credentials; when your apps write to Sheets,
Google will automatically check that your hash and package match the credentials
you entered.

### Enabling the Google Drive API

By now, the Sheets API should be available. To be able to upload files to Google
drive, you will also need to enable the Google Drive API, fortunately, you do
not have to reenter the signing key and package name. Go to the [Google Drive
section of the API Manager][drive_console] and click "ENABLE" to enable the
Drive API.

![Enabling Drive API](images/drive_api.png)

## Setting up the Build

You'll need to include some Google libraries in your gradle build. The library
Expand Down Expand Up @@ -217,6 +227,29 @@ public enum TestType {
}
```

Here is a snippet that uploads an image to Google Drive. The method takes in the
image as a bitmap, and you specify the folder and image name for the upload.

```java
import edu.umd.cmsc436.sheets.Sheets;

...

private void sendToSheets() {
String spreadsheetId = "1ASIF7kZHFFaUNiBndhPKTGYaQgTEbqPNfYO5DVb1Y9Y";
String privateSpreadsheetId = "1MU87u75_qx35qb6TdtizRBeOH1fkO76ufzR47bfZaRQ";
Sheets sheet = new Sheets(this, this, getString(R.string.app_name), spreadsheetId, privateSpreadsheetId);

String folderId = "0B3RViSRC0aoYVDN6MWZUb1RDSVU";
String uploadName = "This is the name of the upload as seen on Drive."
Bitmap imageToUpload = null;

/* Code to set up the bitmap goes here. */

sheet.uploadToDrive(folderId, uploadName, imageToUpload);
}
```

### Callbacks

Your activity must implement the `Sheets.Host` interface, which requires you to
Expand All @@ -232,14 +265,15 @@ public interface Host {
```

The `getRequestCode` method requires you to define unique request codes for the
four different request actions.
five different request actions.

```java
public enum Action {
REQUEST_PERMISSIONS,
REQUEST_ACCOUNT_NAME,
REQUEST_PLAY_SERVICES,
REQUEST_AUTHORIZATION
REQUEST_AUTHORIZATION,
REQUEST_CONNECTION_RESOLUTION
}
```

Expand Down Expand Up @@ -297,6 +331,7 @@ Just talk to me and I'll add you to this organization.
[quickstart]: <https://developers.google.com/sheets/api/quickstart/android>
[signing]: <https://developer.android.com/studio/publish/app-signing.html>
[sheets_console]: <https://console.developers.google.com/flows/enableapi?apiid=sheets.googleapis.com>
[drive_console]: <https://console.developers.google.com/apis/api/drive.googleapis.com/overview>
[library]: <https://developer.android.com/studio/projects/android-library.html>
[console]: <https://console.developers.google.com/apis/credentials>
[release]: <https://github.com/cmsc436/sheets436/releases>
Expand Down
1 change: 1 addition & 0 deletions app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="edu.umd.sheets436">

<uses-permission android:name="android.permission.INTERNET"></uses-permission>
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
Expand Down
27 changes: 27 additions & 0 deletions app/src/main/java/edu/umd/sheets436/MainActivity.java
Original file line number Diff line number Diff line change
@@ -1,11 +1,18 @@
package edu.umd.sheets436;

import android.content.Intent;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.StrictMode;
import android.support.annotation.NonNull;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;

import java.io.IOException;
import java.io.InputStream;
import java.net.URL;

import edu.umd.cmsc436.sheets.Sheets;

public class MainActivity extends AppCompatActivity implements Sheets.Host {
Expand All @@ -14,6 +21,7 @@ public class MainActivity extends AppCompatActivity implements Sheets.Host {
public static final int LIB_AUTHORIZATION_REQUEST_CODE = 1002;
public static final int LIB_PERMISSION_REQUEST_CODE = 1003;
public static final int LIB_PLAY_SERVICES_REQUEST_CODE = 1004;
public static final int LIB_CONNECTION_REQUEST_CODE = 1005;

private Sheets sheet;

Expand All @@ -27,6 +35,23 @@ protected void onCreate(Bundle savedInstanceState) {

float[] trialData = {1.23f, 4.56f, 7.89f};
sheet.writeTrials(Sheets.TestType.LH_TAP, getString(R.string.user_id), trialData);

// The next two lines of code allows network calls on the UI thread. Do not do this in a
// real app. I'm just doing this for ease of coding/reading, since this is a sample of how
// to use the API.
StrictMode.ThreadPolicy policy = new StrictMode.ThreadPolicy.Builder().permitAll().build();
StrictMode.setThreadPolicy(policy);

// Grab some random picture from the Internet.
Bitmap bitmap = null;
try {
URL url = new URL("https://www.umiacs.umd.edu/sites/default/files/styles/medium/public/web-Memon09.jpg");
bitmap = BitmapFactory.decodeStream((InputStream) url.getContent());
} catch (IOException e) {
e.printStackTrace();
}

sheet.uploadToDrive(getString(R.string.CMSC436_test_folder), getString(R.string.image_name), bitmap);
}

@Override
Expand All @@ -51,6 +76,8 @@ public int getRequestCode(Sheets.Action action) {
return LIB_PERMISSION_REQUEST_CODE;
case REQUEST_PLAY_SERVICES:
return LIB_PLAY_SERVICES_REQUEST_CODE;
case REQUEST_CONNECTION_RESOLUTION:
return LIB_CONNECTION_REQUEST_CODE;
default:
return -1;
}
Expand Down
1 change: 1 addition & 0 deletions app/src/main/res/layout/activity_main.xml
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
tools:context="edu.umd.sheets436.MainActivity">

<TextView
android:id="@+id/hello_world"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Hello World!"
Expand Down
2 changes: 2 additions & 0 deletions app/src/main/res/values/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,7 @@
<string name="CMSC436_central_spreadsheet">1YvI3CjS4ZlZQDYi5PaiA7WGGcoCsZfLoSFM0IdvdbDU</string>
<string name="CMSC436_testing_spreadsheet">1ASIF7kZHFFaUNiBndhPKTGYaQgTEbqPNfYO5DVb1Y9Y</string>
<string name="CMSC436_private_test_spreadsheet">1MU87u75_qx35qb6TdtizRBeOH1fkO76ufzR47bfZaRQ</string>
<string name="CMSC436_test_folder">0B3RViSRC0aoYVDN6MWZUb1RDSVU</string>
<string name="user_id">Your user ID belongs here!</string>
<string name="image_name">The name of your image upload goes here!</string>
</resources>
Binary file added images/drive_api.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
7 changes: 6 additions & 1 deletion sheets436/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ android {
minSdkVersion 22
targetSdkVersion 25
versionCode 1
versionName "0.0.3"
versionName "0.0.4"

testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
archivesBaseName = "${archivesBaseName}-" + versionName
Expand All @@ -28,6 +28,7 @@ dependencies {
})
compile 'com.android.support:appcompat-v7:25.3.1'
compile 'com.google.android.gms:play-services-auth:10.2.1'
compile 'com.google.android.gms:play-services-drive:10.2.1'
compile('com.google.api-client:google-api-client-android:1.22.0') {
exclude group: 'org.apache.httpcomponents'
exclude group: 'com.google.code.findbugs'
Expand All @@ -36,4 +37,8 @@ dependencies {
exclude group: 'org.apache.httpcomponents'
exclude group: 'com.google.code.findbugs'
}
compile('com.google.apis:google-api-services-drive:v3-rev69-1.22.0') {
exclude group: 'org.apache.httpcomponents'
exclude group: 'com.google.code.findbugs'
}
}
85 changes: 75 additions & 10 deletions sheets436/src/main/java/edu/umd/cmsc436/sheets/Sheets.java
Original file line number Diff line number Diff line change
Expand Up @@ -5,17 +5,23 @@
import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.content.IntentSender;
import android.content.SharedPreferences;
import android.content.pm.PackageManager;
import android.graphics.Bitmap;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
import android.os.Build;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.v4.app.ActivityCompat;
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.api.client.googleapis.extensions.android.gms.auth.GoogleAccountCredential;
import com.google.api.client.util.ExponentialBackOff;
import com.google.api.services.sheets.v4.SheetsScopes;
Expand All @@ -28,7 +34,7 @@
* Class to instantiate and hook into parts of the normal app
*/

public class Sheets {
public class Sheets implements GoogleApiClient.ConnectionCallbacks, GoogleApiClient.OnConnectionFailedListener {

private final String[] PERMISSIONS = new String[] {
Manifest.permission.GET_ACCOUNTS
Expand All @@ -41,15 +47,23 @@ public class Sheets {
private Activity hostActivity;
private GoogleAccountCredential credentials;

private boolean cache_is_private;
private ServiceType cache_service;
private TestType cache_type;
private String cache_userId;
private String cache_folderId;
private String cache_fileName;
private Bitmap cache_image;
private float cache_value;
private float[] cache_trials;
private String appName;
private String spreadsheetId;
private String privateSpreadsheetId;

private enum ServiceType {
WriteData,
WriteTrials
}

public Sheets(Host host, Activity hostActivity, String appName, String spreadsheetId, String privateSpreadsheetId) {
this.host = host;
this.hostActivity = hostActivity;
Expand All @@ -62,7 +76,7 @@ public Sheets(Host host, Activity hostActivity, String appName, String spreadshe
}

public void writeData (TestType testType, String userId, float value) {
cache_is_private = false;
cache_service = ServiceType.WriteData;
cache_type = testType;
cache_userId = userId;
cache_value = value;
Expand All @@ -73,7 +87,7 @@ public void writeData (TestType testType, String userId, float value) {
}

public void writeTrials (TestType testType, String userId, float[] trials) {
cache_is_private = true;
cache_service = ServiceType.WriteTrials;
cache_type = testType;
cache_userId = userId;
cache_trials = trials;
Expand All @@ -83,6 +97,46 @@ public void writeTrials (TestType testType, String userId, float[] trials) {
}
}

public void uploadToDrive(String folderId, String fileName, Bitmap image) {
cache_folderId = folderId;
cache_fileName = fileName;
cache_image = image;

new GoogleApiClient.Builder(hostActivity)
.addApi(Drive.API)
.addScope(Drive.SCOPE_FILE)
.addConnectionCallbacks(this)
.addOnConnectionFailedListener(this)
.build()
.connect();
}

@Override
public void onConnected(@Nullable Bundle bundle) {
launchUploadToDriveTask();
}

@Override
public void onConnectionSuspended(int i) {
}

@Override
public void onConnectionFailed(@NonNull ConnectionResult connectionResult) {
if (connectionResult.hasResolution()) {
try {
connectionResult.startResolutionForResult(hostActivity, host.getRequestCode(Action.REQUEST_CONNECTION_RESOLUTION));
} catch (IntentSender.SendIntentException e) {
// Unable to resolve, message user appropriately
host.notifyFinished(e);
}
}
}

private void launchUploadToDriveTask() {
UploadToDriveTask uploadToDriveTask = new UploadToDriveTask(credentials, appName, host, hostActivity);
uploadToDriveTask.execute(new UploadToDriveTask.DrivePayload(cache_folderId, cache_fileName, cache_image));
}

public void onRequestPermissionsResult (int requestCode, @NonNull String permissions[], @NonNull int[] grantResults) {
if (requestCode == host.getRequestCode(Action.REQUEST_PERMISSIONS)) {
if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
Expand Down Expand Up @@ -111,14 +165,23 @@ public void onActivityResult(int requestCode, int resultCode, Intent data) {
if (resultCode == RESULT_OK) {
resume();
}
} else if (requestCode == host.getRequestCode(Action.REQUEST_CONNECTION_RESOLUTION)) {
if (resultCode == RESULT_OK) {
launchUploadToDriveTask();
}
}
}

private void resume() {
if (cache_is_private) {
writeTrials(cache_type, cache_userId, cache_trials);
} else {
writeData(cache_type, cache_userId, cache_value);
switch (cache_service) {
case WriteData:
writeData(cache_type, cache_userId, cache_value);
break;
case WriteTrials:
writeTrials(cache_type, cache_userId, cache_trials);
break;
default:
break;
}
}

Expand Down Expand Up @@ -181,7 +244,8 @@ public enum Action {
REQUEST_PERMISSIONS,
REQUEST_ACCOUNT_NAME,
REQUEST_PLAY_SERVICES,
REQUEST_AUTHORIZATION
REQUEST_AUTHORIZATION,
REQUEST_CONNECTION_RESOLUTION
}

@SuppressWarnings("WeakerAccess")
Expand All @@ -200,7 +264,8 @@ public enum TestType {
RH_POP("'Balloon Test (RH)'"),
LH_CURL("'Curling Test (LH)'"),
RH_CURL("'Curling Test (RH)'"),
HEAD_SWAY("'Swaying Test'");
HEAD_SWAY("'Swaying Test'"),
INDOOR_WALKING("'Indoor Walking Test");

private final String id;

Expand Down
Loading

0 comments on commit 67da2be

Please sign in to comment.