com.andyscan.gdaademo.GooDrive.java Source code

Java tutorial

Introduction

Here is the source code for com.andyscan.gdaademo.GooDrive.java

Source

package com.andyscan.gdaademo;

/**
 * Copyright 2014 Sean Janson. All Rights Reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 **/

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.Arrays;

import com.google.android.gms.common.api.GoogleApiClient;
import com.google.android.gms.common.api.Status;
import com.google.android.gms.drive.Drive;
import com.google.android.gms.drive.DriveApi.DriveContentsResult;
import com.google.android.gms.drive.DriveApi.MetadataBufferResult;
import com.google.android.gms.drive.DriveContents;
import com.google.android.gms.drive.DriveFile;
import com.google.android.gms.drive.DriveFolder;
import com.google.android.gms.drive.DriveFolder.DriveFileResult;
import com.google.android.gms.drive.DriveFolder.DriveFolderResult;
import com.google.android.gms.drive.DriveId;
import com.google.android.gms.drive.DriveResource.MetadataResult;
import com.google.android.gms.drive.Metadata;
import com.google.android.gms.drive.MetadataBuffer;
import com.google.android.gms.drive.MetadataChangeSet;
import com.google.android.gms.drive.MetadataChangeSet.Builder;
import com.google.android.gms.drive.query.Filter;
import com.google.android.gms.drive.query.Filters;
import com.google.android.gms.drive.query.Query;
import com.google.android.gms.drive.query.SearchableField;
import com.google.api.client.extensions.android.http.AndroidHttp;
import com.google.api.client.googleapis.extensions.android.gms.auth.GoogleAccountCredential;
import com.google.api.client.googleapis.extensions.android.gms.auth.GoogleAuthIOException;
import com.google.api.client.http.FileContent;
import com.google.api.client.http.GenericUrl;
import com.google.api.client.json.gson.GsonFactory;

import com.google.api.services.drive.DriveScopes;
import com.google.api.services.drive.model.File;
import com.google.api.services.drive.model.FileList;
import com.google.api.services.drive.Drive.Files.List;
import com.google.api.services.drive.model.ParentReference;

final class GooDrive {
    private GooDrive() {
    }

    private static GoogleApiClient mGAC;
    private static com.google.api.services.drive.Drive mGOOSvc;

    /************************************************************************************************
     * initialize Google Drive Api
     * @param ctx   activity context
     * @param email  GOO account
     */
    static void init(MainActivity ctx, String email) {
        UT.lg("init GDAA ");
        if (ctx != null && email != null) {
            //connect(false);
            mGAC = new GoogleApiClient.Builder(ctx).addApi(Drive.API).addScope(Drive.SCOPE_FILE)
                    .setAccountName(email).addConnectionCallbacks(ctx).addOnConnectionFailedListener(ctx).build();

            mGOOSvc = new com.google.api.services.drive.Drive.Builder(AndroidHttp.newCompatibleTransport(),
                    new GsonFactory(), GoogleAccountCredential
                            .usingOAuth2(ctx, Arrays.asList(DriveScopes.DRIVE_FILE)).setSelectedAccountName(email))
                                    .build();

        }

    }

    /************************************************************************************************
     * connect / disconnect
     */
    static void connect(boolean bOn) {
        if (mGAC != null) {
            if (bOn) {
                if (!mGAC.isConnected()) {
                    UT.lg("connect ");
                    mGAC.connect();
                }
            } else {
                if (mGAC.isConnected()) {
                    UT.lg("disconnect ");
                    mGAC.disconnect();
                }
            }
        }
    }

    private static boolean isConnected() {
        return mGAC != null && mGAC.isConnected();
    }

    //////////////////////////////////////////////////////////////////////////////////////////////
    // (S)CRU(D) implementation of Google Drive Android API (GDAA) ////////////////////////////
    /************************************************************************************************
     * find file/folder in GOODrive
     * @param titl    file/folder name (optional)
     * @param mime    file/folder mime type (optional)
     * @return        list of file/folder IDs / null on fail
     */
    static ArrayList<GF> search(DriveId prId, String titl, String mime) {
        ArrayList<GF> gfs = new ArrayList<>();

        if (isConnected()) {
            // add query conditions, build query
            ArrayList<Filter> fltrs = new ArrayList<>();
            if (prId != null)
                fltrs.add(Filters.in(SearchableField.PARENTS, prId));
            if (titl != null)
                fltrs.add(Filters.eq(SearchableField.TITLE, titl));
            if (mime != null)
                fltrs.add(Filters.eq(SearchableField.MIME_TYPE, mime));
            Query qry = new Query.Builder().addFilter(Filters.and(fltrs)).build();

            // fire the query
            MetadataBufferResult rslt = Drive.DriveApi.query(mGAC, qry).await();
            if (rslt.getStatus().isSuccess()) {
                MetadataBuffer mdb = null;
                try {
                    mdb = rslt.getMetadataBuffer();
                    for (Metadata md : mdb) {
                        if (md == null || !md.isDataValid() || md.isTrashed())
                            continue;
                        gfs.add(new GF(md.getTitle(), md.getDriveId().encodeToString()));
                    }
                } finally {
                    if (mdb != null)
                        mdb.close();
                }
            }
        }
        return gfs;
    }

    /************************************************************************************************
     * create file/folder in GOODrive
     * @param prId  parent's ID, null for root
     * @param titl  file name
     * @param mime  file mime type
     * @param buf   file contents  (optional, if null, create folder)
     * @return      file id  / null on fail
     */
    static DriveId create(DriveId prId, String titl, String mime, byte[] buf) {
        if (titl == null || !isConnected())
            return null; //------------->>>
        DriveId dId = null;
        DriveFolder pFldr = (prId == null) ? Drive.DriveApi.getRootFolder(mGAC)
                : Drive.DriveApi.getFolder(mGAC, prId);
        if (pFldr == null)
            return null; //----------------->>>

        MetadataChangeSet meta;
        if (buf != null) { // create file
            if (mime != null) { // file must have mime
                DriveContentsResult r1 = Drive.DriveApi.newDriveContents(mGAC).await();
                if (r1 == null || !r1.getStatus().isSuccess())
                    return null; //-------->>>

                meta = new MetadataChangeSet.Builder().setTitle(titl).setMimeType(mime).build();
                DriveFileResult r2 = pFldr.createFile(mGAC, meta, r1.getDriveContents()).await();
                DriveFile dFil = r2 != null && r2.getStatus().isSuccess() ? r2.getDriveFile() : null;
                if (dFil == null)
                    return null; //---------->>>

                r1 = dFil.open(mGAC, DriveFile.MODE_WRITE_ONLY, null).await();
                if ((r1 != null) && (r1.getStatus().isSuccess()))
                    try {
                        Status stts = bytes2Cont(r1.getDriveContents(), buf).commit(mGAC, meta).await();
                        if ((stts != null) && stts.isSuccess()) {
                            MetadataResult r3 = dFil.getMetadata(mGAC).await();
                            if (r3 != null && r3.getStatus().isSuccess()) {
                                dId = r3.getMetadata().getDriveId();
                            }
                        }
                    } catch (Exception e) {
                        UT.le(e);
                    }
            }

        } else {
            meta = new MetadataChangeSet.Builder().setTitle(titl).setMimeType(UT.MIME_FLDR).build();
            DriveFolderResult r1 = pFldr.createFolder(mGAC, meta).await();
            DriveFolder dFld = (r1 != null) && r1.getStatus().isSuccess() ? r1.getDriveFolder() : null;
            if (dFld != null) {
                MetadataResult r2 = dFld.getMetadata(mGAC).await();
                if ((r2 != null) && r2.getStatus().isSuccess()) {
                    dId = r2.getMetadata().getDriveId();
                }
            }
        }
        return dId;
    }

    /************************************************************************************************
     * get file contents
     * @param dId       file driveId
     * @return          file's content  / null on fail
     */
    static byte[] read(DriveId dId) {
        byte[] buf = null;
        if (isConnected()) {
            DriveFile df = Drive.DriveApi.getFile(mGAC, dId);
            DriveContentsResult rslt = df.open(mGAC, DriveFile.MODE_READ_ONLY, null).await();
            if ((rslt != null) && rslt.getStatus().isSuccess()) {
                DriveContents cont = rslt.getDriveContents();
                buf = cont2Bytes(cont); // UT.is2Bytes(cont.getInputStream());
                cont.discard(mGAC); // or cont.commit();  they are equiv if READONLY
            }
        }
        return buf;
    }

    /************************************************************************************************
     * update file in GOODrive
     * @param dId   file  id
     * @param titl  new file name (optional)
     * @param mime  new file mime type (optional, null or MIME_FLDR indicates folder)
     * @param buf   new file contents (optional)
     * @return       success status
     */
    static boolean update(DriveId dId, String titl, String mime, String desc, byte[] buf) {
        if (dId == null || !isConnected())
            return false; //------------>>>

        Boolean bOK = false;
        Builder mdBd = new MetadataChangeSet.Builder();
        if (titl != null)
            mdBd.setTitle(titl);
        if (mime != null)
            mdBd.setMimeType(mime);
        if (desc != null)
            mdBd.setDescription(desc);
        MetadataChangeSet meta = mdBd.build();

        if (mime == null || UT.MIME_FLDR.equals(mime)) {
            DriveFolder dFldr = Drive.DriveApi.getFolder(mGAC, dId);
            MetadataResult r1 = dFldr.updateMetadata(mGAC, meta).await();
            bOK = (r1 != null) && r1.getStatus().isSuccess();

        } else {
            DriveFile dFile = Drive.DriveApi.getFile(mGAC, dId);
            MetadataResult r1 = dFile.updateMetadata(mGAC, meta).await();
            if ((r1 != null) && r1.getStatus().isSuccess() && buf != null) {
                DriveContentsResult r2 = dFile.open(mGAC, DriveFile.MODE_WRITE_ONLY, null).await();
                if (r2.getStatus().isSuccess()) {
                    Status r3 = bytes2Cont(r2.getDriveContents(), buf).commit(mGAC, meta).await();
                    bOK = (r3 != null && r3.isSuccess());
                }
            }
        }
        return bOK;
    }

    /************************************************************************************************
     * builds a file tree MYROOT/yyyy-mm/yymmdd-hhmmss.jpg
     * @param root  MYROOT
     * @param titl  new file name
     * @param buf   new file contents
     * @return      file Id
     */
    static DriveId createTreeGDAA(String root, String titl, byte[] buf) {
        if (root == null || titl == null)
            return null;
        DriveId dId = findOrCreateFolder((DriveId) null, root);
        if (dId != null) {
            dId = findOrCreateFolder(dId, UT.titl2Month(titl));
            if (dId != null) {
                return create(dId, titl + UT.JPEG_EXT, UT.MIME_JPEG, buf);
            }
        }
        return null;
    }

    /************************************************************************************************
     * runs a test scanning GooDrive, downloading and updating jpegs
     * @param root  MYROOT
     */
    static ArrayList<GF> testTreeGDAA(String root) {
        ArrayList<GF> gfs0 = search((DriveId) null, root, null);
        if (gfs0 != null)
            for (GF gf0 : gfs0) {
                ArrayList<GF> gfs1 = search(DriveId.decodeFromString(gf0.id), null, null);
                if (gfs1 != null)
                    for (GF gf1 : gfs1) {
                        gfs0.add(gf1);
                        ArrayList<GF> gfs2 = search(DriveId.decodeFromString(gf1.id), null, null);
                        if (gfs2 != null)
                            for (GF gf2 : gfs2) {
                                byte[] buf = read(DriveId.decodeFromString(gf2.id));
                                if (buf != null) {
                                    gf2.titl += (", " + (buf.length / 1024) + " kB ");
                                } else {
                                    gf2.titl += (" failed to download ");
                                }
                                update(DriveId.decodeFromString(gf2.id), null, null, "seen " + UT.time2Titl(null),
                                        null);
                                gfs0.add(gf2);
                            }
                    }
            }
        return gfs0;
    }

    private static DriveId findOrCreateFolder(DriveId prnt, String titl) {
        ArrayList<GF> gfs = search(prnt, titl, UT.MIME_FLDR);
        if (gfs.size() > 0) {
            return DriveId.decodeFromString(gfs.get(0).id);
        }
        return create(prnt, titl, null, null);
    }

    private static DriveContents bytes2Cont(DriveContents driveContents, byte[] buf) {
        OutputStream os = driveContents.getOutputStream();
        try {
            os.write(buf);
        } catch (IOException e) {
            UT.le(e);
        } finally {
            try {
                os.close();
            } catch (Exception e) {
                UT.le(e);
            }
        }
        return driveContents;
    }

    private static byte[] cont2Bytes(DriveContents contents) {
        BufferedReader reader = new BufferedReader(new InputStreamReader(contents.getInputStream()));
        StringBuilder builder = new StringBuilder();
        String line;
        try {
            while ((line = reader.readLine()) != null) {
                builder.append(line);
            }
            return builder.toString().getBytes();
        } catch (Exception e) {
            UT.le(e);
        } finally {
            try {
                reader.close();
            } catch (Exception e) {
                UT.le(e);
            }
        }
        return null;
    }

    //////////////////////////////////////////////////////////////////////////////////////////////
    // (S)CRU(D) implementation of Google APIs Java Client (REST) /////////////////////////
    /************************************************************************************************
     * find file/folder in GOODrive
     * @param prId   parent folder resource id (optional)
     * @param titl   file/folder name (optional)
     * @param mime    file/folder mime type (optional)
     * @return        arraylist of found objects
     */
    static ArrayList<GF> search(String prId, String titl, String mime) {
        ArrayList<GF> gfs = new ArrayList<>();
        if (isConnected()) {
            String qryClause = "'me' in owners and ";
            if (prId != null)
                qryClause += "'" + prId + "' in parents and ";
            if (titl != null)
                qryClause += "title = '" + titl + "' and ";
            if (mime != null)
                qryClause += "mimeType = '" + mime + "' and ";
            qryClause = qryClause.substring(0, qryClause.length() - " and ".length());
            List qry = null;
            try {
                qry = mGOOSvc.files().list().setQ(qryClause)
                        .setFields("items(id, labels/trashed, title), nextPageToken");
                gfs = search(gfs, qry);
            } catch (GoogleAuthIOException gaiEx) { // WTF ???
                try {
                    gfs = search(gfs, qry);
                } catch (Exception g) {
                    UT.le(g);
                }
            } catch (Exception e) {
                UT.le(e);
            }
        }
        return gfs;
    }

    /************************************************************************************************
     * create file/folder in GOODrive
     * @param prId  parent's ID, null for root
     * @param titl  file name
     * @param mime  file mime type
     * @param buf   file content (optional, if null, create folder)
     * @return      file id  / null on fail
     */
    static String create(String prId, String titl, String mime, byte[] buf) {
        String rsid = null;
        if (titl != null && isConnected()) {

            File meta = new File();
            meta.setParents(Arrays.asList(new ParentReference().setId(prId == null ? "root" : prId)));
            meta.setTitle(titl);

            File gFl = null;
            if (buf != null) { // create file
                if (mime != null) { // file must have mime
                    meta.setMimeType(mime);
                    java.io.File jvFl;
                    try {
                        jvFl = UT.bytes2File(buf,
                                java.io.File.createTempFile(UT.TMP_FILENM, null, UT.acx.getCacheDir()));
                        gFl = mGOOSvc.files().insert(meta, new FileContent(mime, jvFl)).execute();
                    } catch (Exception e) {
                        UT.le(e);
                    }
                    if (gFl != null && gFl.getId() != null) {
                        rsid = gFl.getId();
                    }
                }
            } else { // create folder
                meta.setMimeType(UT.MIME_FLDR);
                try {
                    gFl = mGOOSvc.files().insert(meta).execute();
                } catch (Exception e) {
                    UT.le(e);
                }
                if (gFl != null && gFl.getId() != null) {
                    rsid = gFl.getId();
                }
            }
        }
        return rsid;
    }

    /************************************************************************************************
     * get file contents
     * @param rsId      file id
     * @return          file's content  / null on fail
     */
    static byte[] read(String rsId) {
        byte[] buf = null;
        if (isConnected() && rsId != null)
            try {
                File gFl = mGOOSvc.files().get(rsId).setFields("downloadUrl").execute();
                if (gFl != null) {
                    InputStream is = mGOOSvc.getRequestFactory()
                            .buildGetRequest(new GenericUrl(gFl.getDownloadUrl())).execute().getContent();
                    buf = UT.is2Bytes(is);
                }
            } catch (Exception e) {
                UT.le(e);
            }
        return buf;
    }

    /************************************************************************************************
     * update file in GOODrive
     * @param rsid  file  id
     * @param titl  new file name (optional)
     * @param mime  new file mime type (optional, null or MIME_FLDR indicates folder)
     * @param buf   new file content (optional)
     * @return       success status
     */
    static boolean update(String rsid, String titl, String mime, String desc, byte[] buf) {
        Boolean bOK = false;
        java.io.File jvFl = null;
        if (mGOOSvc != null && rsid != null)
            try {
                File body = new File();
                if (titl != null)
                    body.setTitle(titl);
                if (mime != null)
                    body.setMimeType(mime);
                if (desc != null)
                    body.setDescription(desc);
                jvFl = UT.bytes2File(buf, java.io.File.createTempFile(UT.TMP_FILENM, null, UT.acx.getCacheDir()));
                FileContent cont = jvFl != null ? new FileContent(mime, jvFl) : null;
                File gFl = (cont == null) ? mGOOSvc.files().patch(rsid, body).execute()
                        : mGOOSvc.files().update(rsid, body, cont).setOcr(false).execute();
                bOK = gFl != null && gFl.getId() != null;
            } catch (Exception e) {
                UT.le(e);
            } finally {
                if (jvFl != null)
                    jvFl.delete();
            }
        return bOK;
    }

    /************************************************************************************************
     * builds a file tree MYROOT/yyyy-mm/yymmdd-hhmmss.jpg
     * @param root  MYROOT
     * @param titl  new file name
     * @param buf   new file contents
     */
    static void createTreeREST(String root, String titl, byte[] buf) {
        if (root != null && titl != null) {
            String rsid = findOrCreateFolder("root", root);
            if (rsid != null) {
                rsid = findOrCreateFolder(rsid, UT.titl2Month(titl));
                if (rsid != null) {
                    create(rsid, titl + UT.JPEG_EXT, UT.MIME_JPEG, buf);
                }
            }
        }
    }

    /************************************************************************************************
     * runs a test scanning GooDrive, downloading and updating jpegs
     * @param root  MYROOT
     */
    static ArrayList<GF> testTreeREST(String root) {
        ArrayList<GF> gfs0 = search((String) null, root, null);
        if (gfs0 != null) {
            for (GF gf0 : gfs0) {
                ArrayList<GF> gfs1 = search(gf0.id, null, null);
                if (gfs1 != null) {
                    gfs0.addAll(gfs1);
                    for (GF gf1 : gfs1) {
                        ArrayList<GF> gfs2 = search(gf1.id, null, null);
                        if (gfs2 != null) {
                            for (GF gf2 : gfs2) {
                                byte[] buf = read(gf2.id);
                                if (buf != null) {
                                    gf2.titl += (", " + (buf.length / 1024) + " kB ");
                                } else {
                                    gf2.titl += (" failed to download ");
                                }
                                update(gf2.id, null, null, "seen " + UT.time2Titl(null), null);
                                gfs0.add(gf2);
                            }
                        }
                    }
                }
            }
        }
        return gfs0;
    }

    private static ArrayList<GF> search(ArrayList<GF> gfs, List qry) throws IOException {
        String npTok = null;
        if (qry != null)
            do {
                FileList gLst = qry.execute();
                if (gLst != null) {
                    for (File gFl : gLst.getItems()) {
                        if (gFl.getLabels().getTrashed())
                            continue;
                        gfs.add(new GF(gFl.getTitle(), gFl.getId()));
                    } //else UT.lg("failed " + gFl.getTitle());
                    npTok = gLst.getNextPageToken();
                    qry.setPageToken(npTok);
                }
            } while (npTok != null && npTok.length() > 0); //UT.lg("found " + vlss.size());
        return gfs;
    }

    private static String findOrCreateFolder(String prnt, String titl) {
        ArrayList<GF> gfs = search(prnt, titl, UT.MIME_FLDR);
        if (gfs.size() > 0) {
            return gfs.get(0).id;
        }
        return create(prnt, titl, null, null);
    }

    final static class GF {
        String titl, id;

        GF(String t, String i) {
            titl = t;
            id = i;
        }
    }

}

/***
 //DriveId dId = md.getDriveId();
 //DriveId.decodeFromString(dId.encodeToString())
 //dId.getResourceId()
 //md.getDescription(), md.getTitle(),
 //md.getAlternateLink(), md.getEmbedLink(), md.getWebContentLink(), md.getWebViewLink()
 ***/