├── .gitignore ├── .idea ├── .name ├── codeStyleSettings.xml ├── compiler.xml ├── copyright │ └── profiles_settings.xml ├── encodings.xml ├── gradle.xml ├── inspectionProfiles │ ├── Project_Default.xml │ └── profiles_settings.xml ├── misc.xml ├── modules.xml ├── runConfigurations.xml └── vcs.xml ├── GDAADemo.iml ├── app ├── .gitignore ├── app.iml ├── build.gradle ├── proguard-rules.pro └── src │ └── main │ ├── AndroidManifest.xml │ ├── java │ └── com │ │ └── spjanson │ │ └── gdaademo │ │ ├── GDAA.java │ │ ├── MainActivity.java │ │ └── UT.java │ └── res │ ├── drawable-hdpi │ ├── ic_action_download.png │ ├── ic_action_remove.png │ └── ic_action_upload.png │ ├── drawable-mdpi │ ├── ic_action_download.png │ ├── ic_action_remove.png │ └── ic_action_upload.png │ ├── drawable-xhdpi │ ├── ic_action_download.png │ ├── ic_action_remove.png │ └── ic_action_upload.png │ ├── drawable-xxhdpi │ ├── ic_action_download.png │ ├── ic_action_remove.png │ └── ic_action_upload.png │ ├── layout │ └── activity_main.xml │ ├── menu │ └── menu_main.xml │ ├── mipmap-hdpi │ └── ic_launcher.png │ ├── mipmap-mdpi │ └── ic_launcher.png │ ├── mipmap-xhdpi │ └── ic_launcher.png │ ├── mipmap-xxhdpi │ └── ic_launcher.png │ ├── values-w820dp │ └── dimens.xml │ └── values │ ├── dimens.xml │ ├── strings.xml │ └── styles.xml ├── build.gradle ├── gradle.properties ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── readme.txt └── settings.gradle /.gitignore: -------------------------------------------------------------------------------- 1 | .gradle 2 | /local.properties 3 | /.idea/workspace.xml 4 | /.idea/libraries 5 | .DS_Store 6 | /build 7 | /captures 8 | -------------------------------------------------------------------------------- /.idea/.name: -------------------------------------------------------------------------------- 1 | GDAADemo -------------------------------------------------------------------------------- /.idea/codeStyleSettings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 227 | 229 | -------------------------------------------------------------------------------- /.idea/compiler.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /.idea/copyright/profiles_settings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /.idea/encodings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /.idea/gradle.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 18 | 19 | -------------------------------------------------------------------------------- /.idea/inspectionProfiles/Project_Default.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 14 | -------------------------------------------------------------------------------- /.idea/inspectionProfiles/profiles_settings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 7 | -------------------------------------------------------------------------------- /.idea/misc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 19 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 46 | -------------------------------------------------------------------------------- /.idea/modules.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /.idea/runConfigurations.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 11 | 12 | -------------------------------------------------------------------------------- /.idea/vcs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /GDAADemo.iml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /app/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /app/app.iml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 8 | 9 | 10 | 11 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | -------------------------------------------------------------------------------- /app/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.application' 2 | 3 | android { 4 | compileSdkVersion 23 5 | buildToolsVersion '23.0.0' 6 | 7 | defaultConfig { 8 | applicationId "com.spjanson.gdaademo" 9 | minSdkVersion 16 10 | targetSdkVersion 22 11 | versionCode 1 12 | versionName "1.0" 13 | } 14 | buildTypes { 15 | release { 16 | minifyEnabled false 17 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 18 | } 19 | } 20 | } 21 | 22 | // https://developers.google.com/android/guides/setup 23 | dependencies { 24 | compile fileTree(include: ['*.jar'], dir: 'libs') 25 | compile 'com.android.support:appcompat-v7:23.0.1' 26 | compile 'com.google.android.gms:play-services-drive:8.1.0' 27 | } 28 | -------------------------------------------------------------------------------- /app/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # By default, the flags in this file are appended to flags specified 3 | # in C:\Users\SeanASUS\AppData\Local\Android\sdk/tools/proguard/proguard-android.txt 4 | # You can edit the include path and order by changing the proguardFiles 5 | # directive in build.gradle. 6 | # 7 | # For more details, see 8 | # http://developer.android.com/guide/developing/tools/proguard.html 9 | 10 | # Add any project specific keep options here: 11 | 12 | # If your project uses WebView with JS, uncomment the following 13 | # and specify the fully qualified class name to the JavaScript interface 14 | # class: 15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 16 | # public *; 17 | #} 18 | -------------------------------------------------------------------------------- /app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 10 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /app/src/main/java/com/spjanson/gdaademo/GDAA.java: -------------------------------------------------------------------------------- 1 | package com.spjanson.gdaademo; 2 | /** 3 | * Copyright 2015 Sean Janson. All Rights Reserved. 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * Unless required by applicable law or agreed to in writing, software 9 | * distributed under the License is distributed on an "AS IS" BASIS, 10 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 11 | * See the License for the specific language governing permissions and 12 | * limitations under the License. 13 | **/ 14 | 15 | import android.app.Activity; 16 | import android.content.ContentValues; 17 | import android.content.Intent; 18 | import android.content.IntentSender; 19 | import android.os.Bundle; 20 | 21 | import java.io.File; 22 | import java.io.FileInputStream; 23 | import java.io.InputStream; 24 | import java.io.OutputStream; 25 | import java.util.ArrayList; 26 | 27 | import com.google.android.gms.common.ConnectionResult; 28 | import com.google.android.gms.common.api.GoogleApiClient; 29 | import com.google.android.gms.common.api.Status; 30 | import com.google.android.gms.drive.Drive; 31 | import com.google.android.gms.drive.DriveApi.MetadataBufferResult; 32 | import com.google.android.gms.drive.DriveApi.DriveContentsResult; 33 | import com.google.android.gms.drive.DriveContents; 34 | import com.google.android.gms.drive.DriveFile; 35 | import com.google.android.gms.drive.DriveFolder; 36 | import com.google.android.gms.drive.DriveFolder.DriveFileResult; 37 | import com.google.android.gms.drive.DriveFolder.DriveFolderResult; 38 | import com.google.android.gms.drive.DriveId; 39 | import com.google.android.gms.drive.DriveResource; 40 | import com.google.android.gms.drive.DriveResource.MetadataResult; 41 | import com.google.android.gms.drive.Metadata; 42 | import com.google.android.gms.drive.MetadataBuffer; 43 | import com.google.android.gms.drive.MetadataChangeSet; 44 | import com.google.android.gms.drive.MetadataChangeSet.Builder; 45 | import com.google.android.gms.drive.OpenFileActivityBuilder; 46 | import com.google.android.gms.drive.query.Filter; 47 | import com.google.android.gms.drive.query.Filters; 48 | import com.google.android.gms.drive.query.Query; 49 | import com.google.android.gms.drive.query.SearchableField; 50 | 51 | final class GDAA { private GDAA() {} 52 | interface ConnectCBs { 53 | void onConnFail(ConnectionResult connResult); 54 | void onConnOK(); 55 | } 56 | private static GoogleApiClient mGAC; 57 | private static ConnectCBs mConnCBs; 58 | 59 | /************************************************************************************************ 60 | * initialize Google Drive Api 61 | * @param act activity context 62 | */ 63 | static boolean init(Activity act) { 64 | if (act != null) { 65 | String email = UT.AM.getEmail(); //UT.lg("emil " + email); 66 | if (email != null) try { 67 | mConnCBs = (ConnectCBs) act; 68 | mGAC = new GoogleApiClient.Builder(act) 69 | .addApi(Drive.API) 70 | .addScope(Drive.SCOPE_FILE) 71 | .addScope(Drive.SCOPE_APPFOLDER) 72 | .addConnectionCallbacks(new GoogleApiClient.ConnectionCallbacks() { 73 | @Override 74 | public void onConnectionSuspended(int i) { 75 | } 76 | 77 | @Override 78 | public void onConnected(Bundle bundle) { 79 | mConnCBs.onConnOK(); 80 | } 81 | }) 82 | .addOnConnectionFailedListener(new GoogleApiClient.OnConnectionFailedListener() { 83 | @Override 84 | public void onConnectionFailed(ConnectionResult connectionResult) { 85 | mConnCBs.onConnFail(connectionResult); 86 | } 87 | }) 88 | .setAccountName(email) 89 | .build(); 90 | return true; 91 | } catch (Exception e) {UT.le(e);} 92 | } 93 | return false; 94 | } 95 | /** 96 | * connect connects GoogleApiClient 97 | */ 98 | static void connect() { 99 | if (UT.AM.getEmail() != null && mGAC != null && !mGAC.isConnecting() && !mGAC.isConnected()) { //UT.lg("conn"); 100 | mGAC.connect(); 101 | } 102 | } 103 | /** 104 | * disconnect disconnects GoogleApiClient 105 | */ 106 | static void disconnect() { 107 | if (mGAC != null && mGAC.isConnected()) { 108 | mGAC.disconnect(); 109 | } 110 | } 111 | 112 | /************************************************************************************************ 113 | * find folder in GOODrive 114 | * @param prnId parent ID (optional), 115 | * null searches full drive, 116 | * "root" searches Drive root 117 | * "appfolder" searches Drive app folder 118 | * @param titl file/folder name (optional) 119 | * @param mime file/folder mime type (optional) 120 | * @return arraylist of found objects 121 | */ 122 | static ArrayList search(String prnId, String titl, String mime) { 123 | ArrayList gfs = new ArrayList<>(); 124 | if (mGAC != null && mGAC.isConnected()) try { 125 | // add query conditions, build query 126 | ArrayList fltrs = new ArrayList<>(); 127 | if (prnId != null) { 128 | if (prnId.equalsIgnoreCase("root")) { 129 | fltrs.add(Filters.in(SearchableField.PARENTS, Drive.DriveApi.getRootFolder(mGAC).getDriveId())); 130 | } else if (prnId.equalsIgnoreCase("appfolder")) { 131 | fltrs.add(Filters.in(SearchableField.PARENTS, Drive.DriveApi.getAppFolder(mGAC).getDriveId())); 132 | } else { 133 | fltrs.add(Filters.in(SearchableField.PARENTS,DriveId.decodeFromString(prnId))); 134 | } 135 | } 136 | if (titl != null) fltrs.add(Filters.eq(SearchableField.TITLE, titl)); 137 | if (mime != null) fltrs.add(Filters.eq(SearchableField.MIME_TYPE, mime)); 138 | Query qry = new Query.Builder().addFilter(Filters.and(fltrs)).build(); 139 | 140 | // fire the query 141 | MetadataBufferResult rslt = Drive.DriveApi.query(mGAC, qry).await(); 142 | if (rslt.getStatus().isSuccess()) { 143 | MetadataBuffer mdb = null; 144 | try { 145 | mdb = rslt.getMetadataBuffer(); 146 | for (Metadata md : mdb) { 147 | if (md == null || !md.isDataValid() || md.isTrashed()) continue; 148 | gfs.add(UT.newCVs(md.getTitle(), md.getDriveId().encodeToString(), md.getMimeType())); 149 | } 150 | } finally { if (mdb != null) mdb.close(); } 151 | } 152 | } catch (Exception e) { UT.le(e); } 153 | return gfs; 154 | } 155 | /************************************************************************************************ 156 | * create file/folder in GOODrive 157 | * @param prnId parent's ID, null or "root" for root, "appfolder" for app folder 158 | * @param titl file name 159 | * @return file id / null on fail 160 | */ 161 | static String createFolder(String prnId, String titl) { 162 | DriveId dId = null; 163 | if (mGAC != null && mGAC.isConnected() && titl != null) try { 164 | DriveFolder pFldr; 165 | if (prnId != null) { 166 | if (prnId.equalsIgnoreCase("root")) { 167 | pFldr = Drive.DriveApi.getRootFolder(mGAC); 168 | } else if (prnId.equalsIgnoreCase("appfolder")) { 169 | pFldr = Drive.DriveApi.getAppFolder(mGAC); 170 | } else { 171 | pFldr = Drive.DriveApi.getFolder(mGAC, DriveId.decodeFromString(prnId)); 172 | } 173 | } else 174 | pFldr = Drive.DriveApi.getRootFolder(mGAC); 175 | if (pFldr == null) return null; //----------------->>> 176 | 177 | MetadataChangeSet meta; 178 | meta = new Builder().setTitle(titl).setMimeType(UT.MIME_FLDR).build(); 179 | DriveFolderResult r1 = pFldr.createFolder(mGAC, meta).await(); 180 | DriveFolder dFld = (r1 != null) && r1.getStatus().isSuccess() ? r1.getDriveFolder() : null; 181 | if (dFld != null) { 182 | MetadataResult r2 = dFld.getMetadata(mGAC).await(); 183 | if ((r2 != null) && r2.getStatus().isSuccess()) { 184 | dId = r2.getMetadata().getDriveId(); 185 | } 186 | } 187 | } catch (Exception e) { UT.le(e); } 188 | return dId == null ? null : dId.encodeToString(); 189 | } 190 | /************************************************************************************************ 191 | * create file in GOODrive 192 | * @param prnId parent's ID, (null or "root") for root 193 | * @param titl file name 194 | * @param mime file mime type 195 | * @param file file (with content) to create 196 | * @return file id / null on fail 197 | */ 198 | static String createFile(String prnId, String titl, String mime, File file) { 199 | DriveId dId = null; 200 | if (mGAC != null && mGAC.isConnected() && titl != null && mime != null && file != null) try { 201 | DriveFolder pFldr = (prnId == null || prnId.equalsIgnoreCase("root")) ? 202 | Drive.DriveApi.getRootFolder(mGAC) : 203 | Drive.DriveApi.getFolder(mGAC, DriveId.decodeFromString(prnId)); 204 | if (pFldr != null) { 205 | DriveContents cont = file2Cont(null, file); 206 | MetadataChangeSet meta = new Builder().setTitle(titl).setMimeType(mime).build(); 207 | DriveFileResult r1 = pFldr.createFile(mGAC, meta, cont).await(); 208 | DriveFile dFil = r1 != null && r1.getStatus().isSuccess() ? r1.getDriveFile() : null; 209 | if (dFil != null) { 210 | MetadataResult r2 = dFil.getMetadata(mGAC).await(); 211 | if (r2 != null && r2.getStatus().isSuccess()) { 212 | dId = r2.getMetadata().getDriveId(); 213 | } 214 | } 215 | } 216 | } catch (Exception e) { UT.le(e); } 217 | return dId == null ? null : dId.encodeToString(); 218 | } 219 | /************************************************************************************************ 220 | * get file contents 221 | * @param id file driveId 222 | * @return file's content / null on fail 223 | */ 224 | static byte[] read(String id) { 225 | byte[] buf = null; 226 | if (mGAC != null && mGAC.isConnected() && id != null) try { 227 | DriveFile df = Drive.DriveApi.getFile(mGAC, DriveId.decodeFromString(id)); 228 | DriveContentsResult rslt = df.open(mGAC, DriveFile.MODE_READ_ONLY, null).await(); 229 | if ((rslt != null) && rslt.getStatus().isSuccess()) { 230 | DriveContents cont = rslt.getDriveContents(); 231 | buf = UT.is2Bytes(cont.getInputStream()); 232 | cont.discard(mGAC); // or cont.commit(); they are equiv if READONLY 233 | } 234 | } catch (Exception e) { UT.le(e); } 235 | return buf; 236 | } 237 | /************************************************************************************************ 238 | * update file in GOODrive 239 | * @param drvId file id 240 | * @param titl new file name (optional) 241 | * @param mime new mime type (optional, "application/vnd.google-apps.folder" indicates folder) 242 | * @param file new file content (optional) 243 | * @return success status 244 | */ 245 | static boolean update(String drvId, String titl, String mime, String desc, File file) { 246 | Boolean bOK = false; 247 | if (mGAC != null && mGAC.isConnected() && drvId != null) try { 248 | Builder mdBd = new Builder(); 249 | if (titl != null) mdBd.setTitle(titl); 250 | if (mime != null) mdBd.setMimeType(mime); 251 | if (desc != null) mdBd.setDescription(desc); 252 | MetadataChangeSet meta = mdBd.build(); 253 | 254 | if (mime != null && UT.MIME_FLDR.equals(mime)) { 255 | DriveFolder dFldr = Drive.DriveApi.getFolder(mGAC, DriveId.decodeFromString(drvId)); 256 | MetadataResult r1 = dFldr.updateMetadata(mGAC, meta).await(); 257 | bOK = (r1 != null) && r1.getStatus().isSuccess(); 258 | 259 | } else { 260 | DriveFile dFile = Drive.DriveApi.getFile(mGAC, DriveId.decodeFromString(drvId)); 261 | MetadataResult r1 = dFile.updateMetadata(mGAC, meta).await(); 262 | if ((r1 != null) && r1.getStatus().isSuccess() && file != null) { 263 | DriveContentsResult r2 = dFile.open(mGAC, DriveFile.MODE_WRITE_ONLY, null).await(); 264 | if (r2.getStatus().isSuccess()) { 265 | DriveContents cont = file2Cont(r2.getDriveContents(), file); 266 | Status r3 = cont.commit(mGAC, meta).await(); 267 | bOK = (r3 != null && r3.isSuccess()); 268 | } 269 | } 270 | } 271 | } catch (Exception e) { UT.le(e); } 272 | return bOK; 273 | } 274 | /************************************************************************************************ 275 | * trash file in GOODrive 276 | * @param drvId file id 277 | * @return success status 278 | */ 279 | static boolean trash(String drvId) { 280 | Boolean bOK = false; 281 | if (mGAC != null && mGAC.isConnected() && drvId != null) try { 282 | DriveId dId = DriveId.decodeFromString(drvId); 283 | DriveResource driveResource; 284 | if (dId.getResourceType() == DriveId.RESOURCE_TYPE_FOLDER) { 285 | driveResource = Drive.DriveApi.getFolder(mGAC, dId); 286 | } else { 287 | driveResource = Drive.DriveApi.getFile(mGAC, dId); 288 | } 289 | Status rslt = driveResource == null ? null : driveResource.trash(mGAC).await(); 290 | bOK = rslt != null && rslt.isSuccess(); 291 | } catch (Exception e) { UT.le(e); } 292 | return bOK; 293 | } 294 | 295 | /************************************************************************************************ 296 | * create file/folder in GOODrive 297 | * @param prnId parent's ID, (null or "root") for root 298 | * @param titl file name 299 | * @param mime file mime type 300 | * @param file file (with content) to create 301 | * @return intent sender/ null on fail 302 | */ 303 | static IntentSender createFileAct(String prnId, String titl, String mime, File file) { 304 | if (mGAC != null && mGAC.isConnected() && titl != null && mime != null && file != null) try { 305 | DriveFolder pFldr = (prnId == null || prnId.equalsIgnoreCase("root")) ? 306 | Drive.DriveApi.getRootFolder(mGAC) : 307 | Drive.DriveApi.getFolder(mGAC, DriveId.decodeFromString(prnId)); 308 | if (pFldr != null) { 309 | DriveContents dc = file2Cont(null, file); 310 | MetadataChangeSet meta = new Builder().setTitle(titl).setMimeType(mime).build(); 311 | 312 | return Drive.DriveApi.newCreateFileActivityBuilder() 313 | .setActivityStartFolder(pFldr.getDriveId()) 314 | .setInitialMetadata(meta).setInitialDriveContents(dc) 315 | .build(mGAC); 316 | } 317 | } catch (Exception e) { UT.le(e); } 318 | return null; 319 | } 320 | static String getId(Intent data){ 321 | return ((DriveId)data.getParcelableExtra(OpenFileActivityBuilder.EXTRA_RESPONSE_DRIVE_ID)).encodeToString(); 322 | } 323 | 324 | /************************************************************************************************ 325 | * pick a file in GOODrive 326 | * @param prnId parent's ID, (null or "root") for root 327 | * @param mimes file mime types 328 | * @return intent sender/ null on fail 329 | */ 330 | static IntentSender pickFile(String prnId, String[] mimes) { 331 | if (mGAC != null && mGAC.isConnected() && mimes != null) try { 332 | DriveFolder pFldr = (prnId == null || prnId.equalsIgnoreCase("root")) ? 333 | Drive.DriveApi.getRootFolder(mGAC) : 334 | Drive.DriveApi.getFolder(mGAC, DriveId.decodeFromString(prnId)); 335 | if (pFldr != null) { 336 | return Drive.DriveApi.newOpenFileActivityBuilder() 337 | .setActivityStartFolder(pFldr.getDriveId()) 338 | .setMimeType(mimes) 339 | .build(mGAC); 340 | } 341 | } catch (Exception e) { UT.le(e); } 342 | return null; 343 | } 344 | 345 | /** 346 | * FILE / FOLDER type object inquiry 347 | * 348 | * @param cv oontent values 349 | * @return TRUE if FOLDER, FALSE otherwise 350 | */ 351 | static boolean isFolder(ContentValues cv) { 352 | String gdId = cv.getAsString(UT.GDID); 353 | DriveId dId = gdId != null ? DriveId.decodeFromString(gdId) : null; 354 | return dId != null && dId.getResourceType() == DriveId.RESOURCE_TYPE_FOLDER; 355 | } 356 | 357 | private static DriveContents file2Cont(DriveContents cont, File file) { 358 | if (file == null) return null; //--------------------->>> 359 | if (cont == null) { 360 | DriveContentsResult r1 = Drive.DriveApi.newDriveContents(mGAC).await(); 361 | cont = r1 != null && r1.getStatus().isSuccess() ? r1.getDriveContents() : null; 362 | } 363 | if (cont != null) try { 364 | OutputStream oos = cont.getOutputStream(); 365 | if (oos != null) try { 366 | InputStream is = new FileInputStream(file); 367 | byte[] buf = new byte[4096]; 368 | int c; 369 | while ((c = is.read(buf, 0, buf.length)) > 0) { 370 | oos.write(buf, 0, c); 371 | oos.flush(); 372 | } 373 | } 374 | finally { oos.close();} 375 | return cont; //++++++++++++++++++++++++++++++>>> 376 | } catch (Exception ignore) {} 377 | return null; //--------------------->>> 378 | } 379 | } 380 | 381 | /*** 382 | private static void foo() { 383 | Metadata md = null; 384 | 385 | DriveId dId = md == null ? null : md.getDriveId(); 386 | 387 | // DriveId -> ResourceId 388 | String rsid = dId == null ? null : dId.getResourceId(); 389 | 390 | // ResourceId -> DriveId 391 | DriveApi.DriveIdResult r = Drive.DriveApi.fetchDriveId(mGAC, rsid).await(); 392 | dId = (r == null || !r.getStatus().isSuccess()) ? null : r.getDriveId(); 393 | 394 | // DriveId -> String 395 | String sId = dId == null ? null : dId.encodeToString(); 396 | 397 | // String -> DriveId 398 | dId = DriveId.decodeFromString(sId); 399 | 400 | 401 | // DriveId -> metadata item (title...) 402 | DriveResource.MetadataResult mdr = null; 403 | switch (dId.getResourceType()) { 404 | case DriveId.RESOURCE_TYPE_FILE: 405 | mdr = Drive.DriveApi.getFile(mGAC, dId).getMetadata(mGAC).await(); 406 | break; 407 | case DriveId.RESOURCE_TYPE_FOLDER: 408 | mdr = Drive.DriveApi.getFolder(mGAC, dId).getMetadata(mGAC).await(); 409 | break; 410 | } 411 | if (mdr.getStatus().isSuccess()) 412 | String titl = mdr.getMetadata().getTitle(); 413 | } 414 | 415 | ***/ 416 | -------------------------------------------------------------------------------- /app/src/main/java/com/spjanson/gdaademo/MainActivity.java: -------------------------------------------------------------------------------- 1 | package com.spjanson.gdaademo; 2 | /** 3 | * Copyright 2015 Sean Janson. All Rights Reserved. 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * Unless required by applicable law or agreed to in writing, software 9 | * distributed under the License is distributed on an "AS IS" BASIS, 10 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 11 | * See the License for the specific language governing permissions and 12 | * limitations under the License. 13 | **/ 14 | 15 | import android.accounts.AccountManager; 16 | import android.content.ContentValues; 17 | import android.content.Intent; 18 | import android.content.IntentSender; 19 | import android.os.AsyncTask; 20 | import android.os.Bundle; 21 | import android.support.v7.app.AppCompatActivity; 22 | import android.view.Menu; 23 | import android.view.MenuItem; 24 | import android.widget.TextView; 25 | import android.widget.Toast; 26 | 27 | import com.google.android.gms.auth.GoogleAuthUtil; 28 | import com.google.android.gms.common.AccountPicker; 29 | import com.google.android.gms.common.ConnectionResult; 30 | 31 | import java.io.File; 32 | import java.util.ArrayList; 33 | 34 | public class MainActivity extends AppCompatActivity implements GDAA.ConnectCBs{ 35 | private static final int REQ_ACCPICK = 1; 36 | private static final int REQ_CONNECT = 2; 37 | private static final int REQ_CREATE = 3; 38 | private static final int REQ_PICKFILE = 4; 39 | 40 | private static TextView mDispTxt; 41 | private static boolean mBusy; 42 | 43 | @Override 44 | protected void onCreate(Bundle bundle) { super.onCreate(bundle); 45 | setContentView(R.layout.activity_main); 46 | mDispTxt = (TextView)findViewById(R.id.tvDispText); 47 | if (bundle == null) { 48 | UT.init(this); 49 | if (!GDAA.init(this)) { 50 | startActivityForResult(AccountPicker.newChooseAccountIntent(null, 51 | null, new String[]{GoogleAuthUtil.GOOGLE_ACCOUNT_TYPE}, true, null, null, null, null), 52 | REQ_ACCPICK); 53 | } 54 | } 55 | } 56 | 57 | @Override 58 | protected void onResume() { super.onResume(); 59 | GDAA.connect(); 60 | } 61 | @Override 62 | protected void onPause() { super.onPause(); 63 | GDAA.disconnect(); 64 | } 65 | 66 | @Override 67 | public boolean onCreateOptionsMenu(Menu menu) { 68 | getMenuInflater().inflate(R.menu.menu_main, menu); 69 | return true; 70 | } 71 | @Override 72 | public boolean onOptionsItemSelected(MenuItem item) { 73 | mDispTxt.setText(""); 74 | switch (item.getItemId()) { 75 | case R.id.action_create: { 76 | createTree(UT.time2Titl(null)); 77 | return true; 78 | } 79 | case R.id.action_list: { 80 | testTree(); 81 | return true; 82 | } 83 | case R.id.action_delete: { 84 | deleteTree(); 85 | return true; 86 | } 87 | 88 | case R.id.action_cre_act: { 89 | new Thread(new Runnable() { 90 | @Override 91 | public void run() { 92 | String titl = UT.time2Titl(null); 93 | File fl = UT.str2File("content of " + titl, "tmp" ); 94 | IntentSender is = null; 95 | if (fl != null) { 96 | is = GDAA.createFileAct(null, titl, UT.MIME_TEXT, fl); 97 | fl.delete(); 98 | } 99 | if (is == null) 100 | mDispTxt.append("\n failed " + titl); 101 | else try { 102 | startIntentSenderForResult( is, REQ_CREATE, null, 0, 0, 0); 103 | } catch (Exception e) { UT.le(e); } 104 | } 105 | }).start(); 106 | return true; 107 | } 108 | case R.id.action_pick_act: { 109 | new Thread(new Runnable() { 110 | @Override 111 | public void run() { 112 | //{UT.MIME_FLDR} or {DriveFolder.MIME_TYPE} for folder 113 | IntentSender is = GDAA.pickFile(null, new String[] {UT.MIME_TEXT}); 114 | if (is == null) 115 | mDispTxt.append("\n failed "); 116 | else try { 117 | startIntentSenderForResult( is, REQ_PICKFILE, null, 0, 0, 0); 118 | } catch (Exception e) { UT.le(e); } 119 | } 120 | }).start(); 121 | return true; 122 | } 123 | 124 | case R.id.action_account: { 125 | startActivityForResult(AccountPicker.newChooseAccountIntent( 126 | null, null, new String[]{GoogleAuthUtil.GOOGLE_ACCOUNT_TYPE}, true, null, null, null, null), REQ_ACCPICK); 127 | return true; 128 | } 129 | } 130 | return super.onOptionsItemSelected(item); 131 | } 132 | 133 | @Override 134 | protected void onActivityResult(int request, int result, Intent data) { 135 | switch (request) { 136 | case REQ_CONNECT: 137 | if (result == RESULT_OK) 138 | GDAA.connect(); 139 | else 140 | suicide(R.string.err_author); //---------------------------------->>> 141 | break; 142 | case REQ_ACCPICK: 143 | if (data != null && data.getStringExtra(AccountManager.KEY_ACCOUNT_NAME) != null) 144 | UT.AM.setEmail(data.getStringExtra(AccountManager.KEY_ACCOUNT_NAME)); 145 | if (!GDAA.init(this)) 146 | suicide(R.string.err_author); //---------------------------------->>> 147 | break; 148 | 149 | case REQ_CREATE: 150 | if (result == RESULT_OK) { 151 | mDispTxt.append("\n success " + GDAA.getId(data)); 152 | } else { 153 | mDispTxt.append("\n failed"); 154 | } 155 | break; 156 | case REQ_PICKFILE: 157 | if (result == RESULT_OK) { 158 | mDispTxt.append("\nPICKFILE OK " + GDAA.getId(data)); 159 | } else { 160 | mDispTxt.append("\nPICKFILE FAIL "); 161 | } 162 | break; 163 | } 164 | super.onActivityResult(request, result, data); 165 | } 166 | 167 | // *** connection callbacks *********************************************************** 168 | @Override 169 | public void onConnOK() { 170 | mDispTxt.append("\n\nCONNECTED TO: " + UT.AM.getEmail()); 171 | } 172 | @Override 173 | public void onConnFail(ConnectionResult connResult) { 174 | if (connResult != null && connResult.hasResolution()) try { //UT.lg("connFail - has res"); 175 | connResult.startResolutionForResult(this, REQ_CONNECT); 176 | return; //++++++++++++++++++++++++++++++++++++++++++++++++++++++++>>> 177 | } catch (Exception e) { UT.le(e); } //UT.lg("connFail - no res"); 178 | suicide(R.string.err_author); //---------------------------------->>> 179 | } 180 | 181 | /** 182 | * creates a directory tree to house a text file 183 | * @param titl file name (confirms to 'yyMMdd-HHmmss' and it's name is used 184 | * to create it's parent folder 'yyyy-MM' under a common root 'GDRTDemo' 185 | * GDAADemo ---+--- yyyy-MM ---+--- yyMMdd-HHmmss 186 | * | +--- yyMMdd-HHmmss 187 | * | ... 188 | * +--- yyyy-MM ---+--- yyMMdd-HHmmss 189 | * +--- yyMMdd-HHmmss 190 | * .... 191 | */ 192 | private void createTree(final String titl) { 193 | if (titl != null && !mBusy) { 194 | mDispTxt.setText("UPLOADING\n"); 195 | 196 | new AsyncTask() { 197 | private String findOrCreateFolder(String prnt, String titl){ 198 | ArrayList cvs = GDAA.search(prnt, titl, UT.MIME_FLDR); 199 | String id, txt; 200 | if (cvs.size() > 0) { 201 | txt = "found "; 202 | id = cvs.get(0).getAsString(UT.GDID); 203 | } else { 204 | id = GDAA.createFolder(prnt, titl); 205 | txt = "created "; 206 | } 207 | if (id != null) 208 | txt += titl; 209 | else 210 | txt = "failed " + titl; 211 | publishProgress(txt); 212 | return id; 213 | } 214 | 215 | @Override 216 | protected Void doInBackground(Void... params) { 217 | mBusy = true; 218 | //String rsid = findOrCreateFolder("appfolder", UT.MYROOT); // app folder test 219 | String rsid = findOrCreateFolder("root", UT.MYROOT); 220 | if (rsid != null) { 221 | rsid = findOrCreateFolder(rsid, UT.titl2Month(titl)); 222 | if (rsid != null) { 223 | File fl = UT.str2File("content of " + titl, "tmp" ); 224 | String id = null; 225 | if (fl != null) { 226 | id = GDAA.createFile(rsid, titl, UT.MIME_TEXT, fl); 227 | fl.delete(); 228 | } 229 | if (id != null) 230 | publishProgress("created " + titl); 231 | else 232 | publishProgress("failed " + titl); 233 | } 234 | } 235 | return null; 236 | } 237 | @Override 238 | protected void onProgressUpdate(String... strings) { super.onProgressUpdate(strings); 239 | mDispTxt.append("\n" + strings[0]); 240 | } 241 | @Override 242 | protected void onPostExecute(Void nada) { super.onPostExecute(nada); 243 | mDispTxt.append("\n\nDONE"); 244 | mBusy = false; 245 | } 246 | }.execute(); 247 | } 248 | } 249 | 250 | /** 251 | * scans folder tree created by this app listing folders / files, updating file's 252 | * 'description' meadata in the process 253 | */ 254 | private void testTree() { 255 | if (!mBusy) { 256 | mDispTxt.setText("DOWNLOADING\n"); 257 | new AsyncTask() { 258 | 259 | private void iterate(ContentValues gfParent) { 260 | ArrayList cvs = GDAA.search(gfParent.getAsString(UT.GDID), null, null); 261 | if (cvs != null) for (ContentValues cv : cvs) { 262 | String gdid = cv.getAsString(UT.GDID); 263 | String titl = cv.getAsString(UT.TITL); 264 | 265 | if (GDAA.isFolder(cv)) { 266 | publishProgress(titl); 267 | iterate(cv); 268 | } else { 269 | byte[] buf = GDAA.read(gdid); 270 | if (buf == null) 271 | titl += " failed"; 272 | publishProgress(titl); 273 | String str = buf == null ? "" : new String(buf); 274 | File fl = UT.str2File(str + "\n updated " + UT.time2Titl(null), "tmp" ); 275 | if (fl != null) { 276 | String desc = "seen " + UT.time2Titl(null); 277 | GDAA.update(gdid, null, null, desc, fl); 278 | fl.delete(); 279 | } 280 | } 281 | } 282 | } 283 | 284 | @Override 285 | protected Void doInBackground(Void... params) { 286 | mBusy = true; 287 | //ArrayList gfMyRoot = GDAA.search("appfolder", UT.MYROOT, null); // app folder test 288 | ArrayList gfMyRoot = GDAA.search("root", UT.MYROOT, null); 289 | if (gfMyRoot != null && gfMyRoot.size() == 1 ){ 290 | publishProgress(gfMyRoot.get(0).getAsString(UT.TITL)); 291 | iterate(gfMyRoot.get(0)); 292 | } 293 | return null; 294 | } 295 | 296 | @Override 297 | protected void onProgressUpdate(String... strings) { 298 | super.onProgressUpdate(strings); 299 | mDispTxt.append("\n" + strings[0]); 300 | } 301 | 302 | @Override 303 | protected void onPostExecute(Void nada) { 304 | super.onPostExecute(nada); 305 | mDispTxt.append("\n\nDONE"); 306 | mBusy = false; 307 | } 308 | }.execute(); 309 | } 310 | } 311 | 312 | /** 313 | * scans folder tree created by this app deleting folders / files in the process 314 | */ 315 | private void deleteTree() { 316 | if (!mBusy) { 317 | mDispTxt.setText("DELETING\n"); 318 | new AsyncTask() { 319 | 320 | private void iterate(ContentValues gfParent) { 321 | ArrayList cvs = GDAA.search(gfParent.getAsString(UT.GDID), null, null); 322 | if (cvs != null) for (ContentValues cv : cvs) { 323 | String titl = cv.getAsString(UT.TITL); 324 | String gdid = cv.getAsString(UT.GDID); 325 | if (GDAA.isFolder(cv)) 326 | iterate(cv); 327 | publishProgress(" " + titl + (GDAA.trash(gdid) ? " DELETED" : " FAIL")); 328 | } 329 | } 330 | 331 | @Override 332 | protected Void doInBackground(Void... params) { 333 | mBusy = true; 334 | //ArrayList gfMyRoot = GDAA.search("appfolder", UT.MYROOT, null); // app folder test 335 | ArrayList gfMyRoot = GDAA.search("root", UT.MYROOT, null); 336 | if (gfMyRoot != null && gfMyRoot.size() == 1 ){ 337 | ContentValues cv = gfMyRoot.get(0); 338 | iterate(cv); 339 | String titl = cv.getAsString(UT.TITL); 340 | String gdid = cv.getAsString(UT.GDID); 341 | publishProgress(" " + titl + (GDAA.trash(gdid) ? " DELETED" : " FAIL")); 342 | } 343 | return null; 344 | } 345 | 346 | @Override 347 | protected void onProgressUpdate(String... strings) { 348 | super.onProgressUpdate(strings); 349 | mDispTxt.append("\n" + strings[0]); 350 | } 351 | 352 | @Override 353 | protected void onPostExecute(Void nada) { 354 | super.onPostExecute(nada); 355 | mDispTxt.append("\n\nDONE"); 356 | mBusy = false; 357 | } 358 | }.execute(); 359 | } 360 | } 361 | 362 | private void suicide(int rid) { 363 | UT.AM.setEmail(null); 364 | Toast.makeText(this, rid, Toast.LENGTH_LONG).show(); 365 | finish(); 366 | } 367 | } 368 | -------------------------------------------------------------------------------- /app/src/main/java/com/spjanson/gdaademo/UT.java: -------------------------------------------------------------------------------- 1 | package com.spjanson.gdaademo; 2 | /** 3 | * Copyright 2015 Sean Janson. All Rights Reserved. 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * Unless required by applicable law or agreed to in writing, software 9 | * distributed under the License is distributed on an "AS IS" BASIS, 10 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 11 | * See the License for the specific language governing permissions and 12 | * limitations under the License. 13 | */ 14 | 15 | import android.content.ContentValues; 16 | import android.content.Context; 17 | import android.content.SharedPreferences; 18 | import android.preference.PreferenceManager; 19 | import android.util.Log; 20 | 21 | import java.io.BufferedInputStream; 22 | import java.io.BufferedOutputStream; 23 | import java.io.ByteArrayOutputStream; 24 | import java.io.File; 25 | import java.io.FileOutputStream; 26 | import java.io.InputStream; 27 | import java.text.SimpleDateFormat; 28 | import java.util.Date; 29 | import java.util.Locale; 30 | 31 | final class UT { private UT() {} 32 | 33 | private static final String L_TAG = "_X_"; 34 | 35 | static final String MYROOT = "DEMORoot"; 36 | static final String MIME_TEXT = "text/plain"; 37 | static final String MIME_FLDR = "application/vnd.google-apps.folder"; 38 | 39 | static final String TITL = "titl"; 40 | static final String GDID = "gdid"; 41 | static final String MIME = "mime"; 42 | 43 | private static final String TITL_FMT = "yyMMdd-HHmmss"; 44 | 45 | private static SharedPreferences pfs; 46 | static Context acx; 47 | static void init(Context ctx) { 48 | acx = ctx.getApplicationContext(); 49 | pfs = PreferenceManager.getDefaultSharedPreferences(acx); 50 | } 51 | 52 | static class AM { private AM(){} 53 | private static final String ACC_NAME = "account_name"; 54 | private static String mEmail = null; 55 | 56 | static void setEmail(String email) { 57 | UT.pfs.edit().putString(ACC_NAME, (mEmail = email)).apply(); 58 | } 59 | static String getEmail() { 60 | return mEmail != null ? mEmail : (mEmail = UT.pfs.getString(ACC_NAME, null)); 61 | } 62 | } 63 | 64 | static ContentValues newCVs(String titl, String gdId, String mime) { 65 | ContentValues cv = new ContentValues(); 66 | if (titl != null) cv.put(TITL, titl); 67 | if (gdId != null) cv.put(GDID, gdId); 68 | if (mime != null) cv.put(MIME, mime); 69 | return cv; 70 | } 71 | 72 | private static File cchFile(String flNm) { 73 | File cche = UT.acx.getExternalCacheDir(); 74 | return (cche == null || flNm == null) ? null : new File(cche.getPath() + File.separator + flNm); 75 | } 76 | static File str2File(String str, String name) { 77 | if (str == null) return null; 78 | byte[] buf = str.getBytes(); 79 | File fl = cchFile(name); 80 | if (fl == null) return null; 81 | BufferedOutputStream bs = null; 82 | try { 83 | bs = new BufferedOutputStream(new FileOutputStream(fl)); 84 | bs.write(buf); 85 | } catch (Exception e) { le(e); } 86 | finally { 87 | if (bs != null) try { 88 | bs.close(); 89 | } catch (Exception e) { le(e); } 90 | } 91 | return fl; 92 | } 93 | static byte[] is2Bytes(InputStream is) { 94 | byte[] buf = null; 95 | BufferedInputStream bufIS = null; 96 | if (is != null) try { 97 | ByteArrayOutputStream byteBuffer = new ByteArrayOutputStream(); 98 | bufIS = new BufferedInputStream(is); 99 | buf = new byte[4096]; 100 | int cnt; 101 | while ((cnt = bufIS.read(buf)) >= 0) { 102 | byteBuffer.write(buf, 0, cnt); 103 | } 104 | buf = byteBuffer.size() > 0 ? byteBuffer.toByteArray() : null; 105 | } catch (Exception ignore) {} 106 | finally { 107 | try { 108 | if (bufIS != null) bufIS.close(); 109 | } catch (Exception ignore) {} 110 | } 111 | return buf; 112 | } 113 | 114 | static String time2Titl(Long milis) { // time -> yymmdd-hhmmss 115 | Date dt = (milis == null) ? new Date() : (milis >= 0) ? new Date(milis) : null; 116 | return (dt == null) ? null : new SimpleDateFormat(TITL_FMT, Locale.US).format(dt); 117 | } 118 | static String titl2Month(String titl) { 119 | return titl == null ? null : ("20" + titl.substring(0, 2) + "-" + titl.substring(2, 4)); 120 | } 121 | 122 | static void le(Throwable ex) { Log.e(L_TAG, Log.getStackTraceString(ex)); } 123 | static void lg(String msg) { Log.d(L_TAG, msg); } 124 | } 125 | 126 | 127 | -------------------------------------------------------------------------------- /app/src/main/res/drawable-hdpi/ic_action_download.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/seanpjanson/GDAADemo/5b54bd2d4fd4091a573d29eea5ae13550e9f5e0b/app/src/main/res/drawable-hdpi/ic_action_download.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-hdpi/ic_action_remove.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/seanpjanson/GDAADemo/5b54bd2d4fd4091a573d29eea5ae13550e9f5e0b/app/src/main/res/drawable-hdpi/ic_action_remove.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-hdpi/ic_action_upload.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/seanpjanson/GDAADemo/5b54bd2d4fd4091a573d29eea5ae13550e9f5e0b/app/src/main/res/drawable-hdpi/ic_action_upload.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-mdpi/ic_action_download.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/seanpjanson/GDAADemo/5b54bd2d4fd4091a573d29eea5ae13550e9f5e0b/app/src/main/res/drawable-mdpi/ic_action_download.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-mdpi/ic_action_remove.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/seanpjanson/GDAADemo/5b54bd2d4fd4091a573d29eea5ae13550e9f5e0b/app/src/main/res/drawable-mdpi/ic_action_remove.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-mdpi/ic_action_upload.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/seanpjanson/GDAADemo/5b54bd2d4fd4091a573d29eea5ae13550e9f5e0b/app/src/main/res/drawable-mdpi/ic_action_upload.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/ic_action_download.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/seanpjanson/GDAADemo/5b54bd2d4fd4091a573d29eea5ae13550e9f5e0b/app/src/main/res/drawable-xhdpi/ic_action_download.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/ic_action_remove.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/seanpjanson/GDAADemo/5b54bd2d4fd4091a573d29eea5ae13550e9f5e0b/app/src/main/res/drawable-xhdpi/ic_action_remove.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/ic_action_upload.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/seanpjanson/GDAADemo/5b54bd2d4fd4091a573d29eea5ae13550e9f5e0b/app/src/main/res/drawable-xhdpi/ic_action_upload.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/ic_action_download.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/seanpjanson/GDAADemo/5b54bd2d4fd4091a573d29eea5ae13550e9f5e0b/app/src/main/res/drawable-xxhdpi/ic_action_download.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/ic_action_remove.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/seanpjanson/GDAADemo/5b54bd2d4fd4091a573d29eea5ae13550e9f5e0b/app/src/main/res/drawable-xxhdpi/ic_action_remove.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/ic_action_upload.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/seanpjanson/GDAADemo/5b54bd2d4fd4091a573d29eea5ae13550e9f5e0b/app/src/main/res/drawable-xxhdpi/ic_action_upload.png -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_main.xml: -------------------------------------------------------------------------------- 1 | 10 | 11 | 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /app/src/main/res/menu/menu_main.xml: -------------------------------------------------------------------------------- 1 | 6 | 7 | 12 | 13 | 18 | 19 | 24 | 25 | 29 | 30 | 34 | 35 | 39 | 40 | 41 | -------------------------------------------------------------------------------- /app/src/main/res/mipmap-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/seanpjanson/GDAADemo/5b54bd2d4fd4091a573d29eea5ae13550e9f5e0b/app/src/main/res/mipmap-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/seanpjanson/GDAADemo/5b54bd2d4fd4091a573d29eea5ae13550e9f5e0b/app/src/main/res/mipmap-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/seanpjanson/GDAADemo/5b54bd2d4fd4091a573d29eea5ae13550e9f5e0b/app/src/main/res/mipmap-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/seanpjanson/GDAADemo/5b54bd2d4fd4091a573d29eea5ae13550e9f5e0b/app/src/main/res/mipmap-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/values-w820dp/dimens.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 64dp 6 | 7 | -------------------------------------------------------------------------------- /app/src/main/res/values/dimens.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 16dp 4 | 16dp 5 | 6 | -------------------------------------------------------------------------------- /app/src/main/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | GDAADemo 5 | 6 | \n\n 7 | 1/ UPLOAD (upload icon) uploads a text file to Google Drive, creating a simple tree 8 | directory structure in the process.\n 9 | The createTree() method allows for testing of different CRUD primitives (search, 10 | create folder, etc…) in the process.\n\n 11 | 2/ DOWNLOAD (download icon) scans the tree created by the createTree() method. If the 12 | object is a file, it\'s metadata is updated (description field), the content is 13 | downloaded.\n\n 14 | 3/ DELETE (X - delete icon) scans the tree created by the createTree() method and deletes 15 | all the files and folders in the process\n 16 | 17 | 18 | 19 | UPLOAD file 20 | DOWNLOAD all files 21 | DELETE all files 22 | CREATE activity 23 | PICK activity 24 | Select Google Account… 25 | 26 | NO GOOGLE DRIVE ACCESS! 27 | 28 | 29 | -------------------------------------------------------------------------------- /app/src/main/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /build.gradle: -------------------------------------------------------------------------------- 1 | // Top-level build file where you can add configuration options common to all sub-projects/modules. 2 | 3 | buildscript { 4 | repositories { 5 | jcenter() 6 | } 7 | dependencies { 8 | classpath 'com.android.tools.build:gradle:1.3.0' 9 | 10 | // NOTE: Do not place your application dependencies here; they belong 11 | // in the individual module build.gradle files 12 | } 13 | } 14 | 15 | allprojects { 16 | repositories { 17 | jcenter() 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /gradle.properties: -------------------------------------------------------------------------------- 1 | # Project-wide Gradle settings. 2 | 3 | # IDE (e.g. Android Studio) users: 4 | # Gradle settings configured through the IDE *will override* 5 | # any settings specified in this file. 6 | 7 | # For more details on how to configure your build environment visit 8 | # http://www.gradle.org/docs/current/userguide/build_environment.html 9 | 10 | # Specifies the JVM arguments used for the daemon process. 11 | # The setting is particularly useful for tweaking memory settings. 12 | # Default value: -Xmx10248m -XX:MaxPermSize=256m 13 | # org.gradle.jvmargs=-Xmx2048m -XX:MaxPermSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8 14 | 15 | # When configured, Gradle will run in incubating parallel mode. 16 | # This option should only be used with decoupled projects. More details, visit 17 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects 18 | # org.gradle.parallel=true -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/seanpjanson/GDAADemo/5b54bd2d4fd4091a573d29eea5ae13550e9f5e0b/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Wed Apr 10 15:27:10 PDT 2013 2 | distributionBase=GRADLE_USER_HOME 3 | distributionPath=wrapper/dists 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | distributionUrl=https\://services.gradle.org/distributions/gradle-2.2.1-all.zip 7 | -------------------------------------------------------------------------------- /gradlew: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | ############################################################################## 4 | ## 5 | ## Gradle start up script for UN*X 6 | ## 7 | ############################################################################## 8 | 9 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 10 | DEFAULT_JVM_OPTS="" 11 | 12 | APP_NAME="Gradle" 13 | APP_BASE_NAME=`basename "$0"` 14 | 15 | # Use the maximum available, or set MAX_FD != -1 to use that value. 16 | MAX_FD="maximum" 17 | 18 | warn ( ) { 19 | echo "$*" 20 | } 21 | 22 | die ( ) { 23 | echo 24 | echo "$*" 25 | echo 26 | exit 1 27 | } 28 | 29 | # OS specific support (must be 'true' or 'false'). 30 | cygwin=false 31 | msys=false 32 | darwin=false 33 | case "`uname`" in 34 | CYGWIN* ) 35 | cygwin=true 36 | ;; 37 | Darwin* ) 38 | darwin=true 39 | ;; 40 | MINGW* ) 41 | msys=true 42 | ;; 43 | esac 44 | 45 | # For Cygwin, ensure paths are in UNIX format before anything is touched. 46 | if $cygwin ; then 47 | [ -n "$JAVA_HOME" ] && JAVA_HOME=`cygpath --unix "$JAVA_HOME"` 48 | fi 49 | 50 | # Attempt to set APP_HOME 51 | # Resolve links: $0 may be a link 52 | PRG="$0" 53 | # Need this for relative symlinks. 54 | while [ -h "$PRG" ] ; do 55 | ls=`ls -ld "$PRG"` 56 | link=`expr "$ls" : '.*-> \(.*\)$'` 57 | if expr "$link" : '/.*' > /dev/null; then 58 | PRG="$link" 59 | else 60 | PRG=`dirname "$PRG"`"/$link" 61 | fi 62 | done 63 | SAVED="`pwd`" 64 | cd "`dirname \"$PRG\"`/" >&- 65 | APP_HOME="`pwd -P`" 66 | cd "$SAVED" >&- 67 | 68 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 69 | 70 | # Determine the Java command to use to start the JVM. 71 | if [ -n "$JAVA_HOME" ] ; then 72 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 73 | # IBM's JDK on AIX uses strange locations for the executables 74 | JAVACMD="$JAVA_HOME/jre/sh/java" 75 | else 76 | JAVACMD="$JAVA_HOME/bin/java" 77 | fi 78 | if [ ! -x "$JAVACMD" ] ; then 79 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 80 | 81 | Please set the JAVA_HOME variable in your environment to match the 82 | location of your Java installation." 83 | fi 84 | else 85 | JAVACMD="java" 86 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 87 | 88 | Please set the JAVA_HOME variable in your environment to match the 89 | location of your Java installation." 90 | fi 91 | 92 | # Increase the maximum file descriptors if we can. 93 | if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then 94 | MAX_FD_LIMIT=`ulimit -H -n` 95 | if [ $? -eq 0 ] ; then 96 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then 97 | MAX_FD="$MAX_FD_LIMIT" 98 | fi 99 | ulimit -n $MAX_FD 100 | if [ $? -ne 0 ] ; then 101 | warn "Could not set maximum file descriptor limit: $MAX_FD" 102 | fi 103 | else 104 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" 105 | fi 106 | fi 107 | 108 | # For Darwin, add options to specify how the application appears in the dock 109 | if $darwin; then 110 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" 111 | fi 112 | 113 | # For Cygwin, switch paths to Windows format before running java 114 | if $cygwin ; then 115 | APP_HOME=`cygpath --path --mixed "$APP_HOME"` 116 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` 117 | 118 | # We build the pattern for arguments to be converted via cygpath 119 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` 120 | SEP="" 121 | for dir in $ROOTDIRSRAW ; do 122 | ROOTDIRS="$ROOTDIRS$SEP$dir" 123 | SEP="|" 124 | done 125 | OURCYGPATTERN="(^($ROOTDIRS))" 126 | # Add a user-defined pattern to the cygpath arguments 127 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then 128 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" 129 | fi 130 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 131 | i=0 132 | for arg in "$@" ; do 133 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` 134 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option 135 | 136 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition 137 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` 138 | else 139 | eval `echo args$i`="\"$arg\"" 140 | fi 141 | i=$((i+1)) 142 | done 143 | case $i in 144 | (0) set -- ;; 145 | (1) set -- "$args0" ;; 146 | (2) set -- "$args0" "$args1" ;; 147 | (3) set -- "$args0" "$args1" "$args2" ;; 148 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;; 149 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; 150 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; 151 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; 152 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; 153 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; 154 | esac 155 | fi 156 | 157 | # Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules 158 | function splitJvmOpts() { 159 | JVM_OPTS=("$@") 160 | } 161 | eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS 162 | JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME" 163 | 164 | exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@" 165 | -------------------------------------------------------------------------------- /gradlew.bat: -------------------------------------------------------------------------------- 1 | @if "%DEBUG%" == "" @echo off 2 | @rem ########################################################################## 3 | @rem 4 | @rem Gradle startup script for Windows 5 | @rem 6 | @rem ########################################################################## 7 | 8 | @rem Set local scope for the variables with windows NT shell 9 | if "%OS%"=="Windows_NT" setlocal 10 | 11 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 12 | set DEFAULT_JVM_OPTS= 13 | 14 | set DIRNAME=%~dp0 15 | if "%DIRNAME%" == "" set DIRNAME=. 16 | set APP_BASE_NAME=%~n0 17 | set APP_HOME=%DIRNAME% 18 | 19 | @rem Find java.exe 20 | if defined JAVA_HOME goto findJavaFromJavaHome 21 | 22 | set JAVA_EXE=java.exe 23 | %JAVA_EXE% -version >NUL 2>&1 24 | if "%ERRORLEVEL%" == "0" goto init 25 | 26 | echo. 27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 28 | echo. 29 | echo Please set the JAVA_HOME variable in your environment to match the 30 | echo location of your Java installation. 31 | 32 | goto fail 33 | 34 | :findJavaFromJavaHome 35 | set JAVA_HOME=%JAVA_HOME:"=% 36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 37 | 38 | if exist "%JAVA_EXE%" goto init 39 | 40 | echo. 41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 42 | echo. 43 | echo Please set the JAVA_HOME variable in your environment to match the 44 | echo location of your Java installation. 45 | 46 | goto fail 47 | 48 | :init 49 | @rem Get command-line arguments, handling Windowz variants 50 | 51 | if not "%OS%" == "Windows_NT" goto win9xME_args 52 | if "%@eval[2+2]" == "4" goto 4NT_args 53 | 54 | :win9xME_args 55 | @rem Slurp the command line arguments. 56 | set CMD_LINE_ARGS= 57 | set _SKIP=2 58 | 59 | :win9xME_args_slurp 60 | if "x%~1" == "x" goto execute 61 | 62 | set CMD_LINE_ARGS=%* 63 | goto execute 64 | 65 | :4NT_args 66 | @rem Get arguments from the 4NT Shell from JP Software 67 | set CMD_LINE_ARGS=%$ 68 | 69 | :execute 70 | @rem Setup the command line 71 | 72 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 73 | 74 | @rem Execute Gradle 75 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% 76 | 77 | :end 78 | @rem End local scope for the variables with windows NT shell 79 | if "%ERRORLEVEL%"=="0" goto mainEnd 80 | 81 | :fail 82 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 83 | rem the _cmd.exe /c_ return code! 84 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 85 | exit /b 1 86 | 87 | :mainEnd 88 | if "%OS%"=="Windows_NT" endlocal 89 | 90 | :omega 91 | -------------------------------------------------------------------------------- /readme.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/seanpjanson/GDAADemo/5b54bd2d4fd4091a573d29eea5ae13550e9f5e0b/readme.txt -------------------------------------------------------------------------------- /settings.gradle: -------------------------------------------------------------------------------- 1 | include ':app' 2 | --------------------------------------------------------------------------------