Example #1
0
    /**
     * Helper just to avoid copy&paste'ing code.
     *
     * <p>Note: since this contains blocking Drive API calls, this will crash if you try to call it
     * from the main thread, it can only be called from other threads.
     *
     * @return null if the folder can not be found.
     */
    private DriveFolder checkOrCreateRemoteFolder(
        GoogleApiClient googleApiClient, DriveFolder rootFolder, String folderName) {
      // check for STORAGE permission
      if (!canWriteToStorage()) return null;

      Query query =
          new Query.Builder()
              .addFilter(
                  Filters.and(
                      Filters.eq(SearchableField.TITLE, folderName),
                      Filters.contains(SearchableField.MIME_TYPE, "folder")))
              .build();

      DriveApi.MetadataBufferResult result =
          rootFolder.queryChildren(mGoogleApiClient, query).await();

      if (!result.getStatus().isSuccess()) {
        Log.e(
            mActivity.getResources().getString(R.string.app_name),
            "Cannot query folders in the root of Google Drive.");
        return null;
      } else {
        for (Metadata m : result.getMetadataBuffer()) {
          if (m.getTitle().equals(folderName)) {
            // Folder exists - we found it!
            DriveFolder folder = m.getDriveId().asDriveFolder();
            result.getMetadataBuffer().release();
            return folder;
          }
        }
      }

      result.getMetadataBuffer().release();

      // Folder not found; let's create it.
      MetadataChangeSet changeSet = new MetadataChangeSet.Builder().setTitle(folderName).build();

      DriveFolder.DriveFolderResult result1 =
          rootFolder.createFolder(googleApiClient, changeSet).await();

      if (!result1.getStatus().isSuccess()) {
        Log.e(
            mActivity.getResources().getString(R.string.app_name),
            "Error while trying to create the folder \"" + folderName + "\"");
        return null;
      }

      return result1.getDriveFolder();
    }
Example #2
0
    private void syncPhotosForTeam(GoogleApiClient googleApiClient, int teamNumber) {
      if (mTeamNumber >= 0) {

        Log.i(
            mActivity.getResources().getString(R.string.app_name),
            "Beginning photo sync for team " + teamNumber);

        // get the list of local files

        File photosDir = new File(mLocalTeamPhotosFilePath + "/" + teamNumber);

        /** **** get the list of local files ***** */

        // check if that folder exists
        if (!photosDir.isDirectory()) {
          // we have no photos for this team
          if (mRequester != null) mRequester.updatePhotos(new Bitmap[0]);
          googleApiClient.disconnect();
          return;
        }

        File[] listOfFiles = photosDir.listFiles();
        ArrayList<String> arrLocalFiles = new ArrayList<String>();
        for (File file : listOfFiles) {
          // make sure it's an image file
          Bitmap bitmap = BitmapFactory.decodeFile(file.getPath());
          if (bitmap != null) {
            arrLocalFiles.add(file.getPath());
          }
          // else: if it's not a file, then what is it???? .... skip I guess
        }

        // Navigate to the correct folder - there has to be a more efficient way to do this

        DriveFolder rootFolder =
            Drive.DriveApi.getFolder(googleApiClient, mDriveIdTeamPhotosFolder);
        Log.i(
            mActivity.getResources().getString(R.string.app_name), "Local Files: " + arrLocalFiles);

        Query query =
            new Query.Builder()
                .addFilter(Filters.eq(SearchableField.TITLE, "" + teamNumber))
                .build();

        DriveApi.MetadataBufferResult result =
            rootFolder.queryChildren(googleApiClient, query).await();

        DriveFolder teamPhotosFolder = null;
        for (Metadata m : result.getMetadataBuffer()) {
          teamPhotosFolder = m.getDriveId().asDriveFolder();
        }
        result.getMetadataBuffer().close();

        ArrayList<PathAndDriveId> arrRemoteFiles = new ArrayList<PathAndDriveId>();
        if (teamPhotosFolder != null) {
          query =
              new Query.Builder()
                  .addFilter(
                      Filters.eq(SearchableField.MIME_TYPE, "application/vnd.google-apps.photo"))
                  .build();
          result = teamPhotosFolder.queryChildren(googleApiClient, query).await();

          for (Metadata m : result.getMetadataBuffer()) {
            arrRemoteFiles.add(
                new PathAndDriveId(
                    mRemoteToplevelFolderName
                        + "/"
                        + mRemoteTeamFolderName
                        + "/"
                        + mRemoteTeamPhotosFolderName
                        + "/"
                        + mTeamNumber
                        + "/"
                        + m.getTitle(),
                    m.getDriveId(),
                    m.getTitle()));
          }
          result.getMetadataBuffer().close();
        }
        Log.i(
            mActivity.getResources().getString(R.string.app_name),
            "Remote Files: " + arrRemoteFiles);

        // Remove files that are in both lists - these don't need to be synced.
        for (PathAndDriveId remoteFile : arrRemoteFiles) {
          String remotePath = remoteFile.path;
          if (arrLocalFiles.contains(remotePath)) {
            arrRemoteFiles.remove(remoteFile);
            arrLocalFiles.remove(remotePath);
          }
        }

        /** **** Download any Files we're missing locally ***** */
        for (PathAndDriveId remoteFile : arrRemoteFiles) {
          // the Drive API actually makes a local cache of the file, so let's copy the contents into
          // our app's file structure
          DriveApi.DriveContentsResult fileResult =
              remoteFile
                  .driveId
                  .asDriveFile()
                  .open(googleApiClient, DriveFile.MODE_READ_ONLY, null)
                  .await();

          if (!fileResult.getStatus().isSuccess()) {
            // file can't be opened
            continue;
          }

          String localFileToCreate =
              mLocalTeamPhotosFilePath + "/" + teamNumber + "/" + remoteFile.title;
          DriveContents contents = null;
          InputStream in = null;
          FileOutputStream fout = null;
          try {
            // DriveContents object contains pointers to the actual byte stream, which we will
            // manually copy
            contents = fileResult.getDriveContents();
            in = contents.getInputStream();
            fout = new FileOutputStream(localFileToCreate);

            // read bytes from source file and write to destination file
            byte[] b = new byte[1024];
            int noOfBytes = 0;
            while ((noOfBytes = in.read(b)) != -1) fout.write(b, 0, noOfBytes);
            in.close();
            fout.close();
            contents.discard(googleApiClient);
          } catch (FileNotFoundException e) {
            // something went wrong, delete the file we were trying to create
            (new File(localFileToCreate)).delete();
          } catch (IOException e) {
            // something went wrong, delete the file we were trying to create
            (new File(localFileToCreate)).delete();
          }
        }

        /** **** Upload any files that are missing remotely ***** */
        for (String localFile : arrLocalFiles) {

          // if the remote folder does not exist, create it. This should only need to be called
          // once.
          if (teamPhotosFolder == null) {
            MetadataChangeSet changeSet =
                new MetadataChangeSet.Builder().setTitle("" + teamNumber).build();
            DriveFolder.DriveFolderResult folderResult =
                rootFolder.createFolder(googleApiClient, changeSet).await();
            teamPhotosFolder = folderResult.getDriveFolder();
          }

          DriveContents contents = null;
          try {
            FileInputStream in = new FileInputStream(localFile);

            // create a new file in Drive. This works a little different than normal file IO it that
            // you create the file first,
            // then tell it at the end which folder it's part of. Think of "folders" in drive more
            // like "tags" or "labels".
            DriveApi.DriveContentsResult contentResult =
                Drive.DriveApi.newDriveContents(googleApiClient).await();
            contents = contentResult.getDriveContents();
            OutputStream out = contents.getOutputStream();
            // read bytes from source file and write to destination file
            byte[] b = new byte[1024];
            int noOfBytes = 0;
            while ((noOfBytes = in.read(b)) != -1) out.write(b, 0, noOfBytes);
            in.close();
            out.close();
          } catch (FileNotFoundException e) {
            // something went wrong, discard the changes to the Drive file
            if (contents != null) contents.discard(googleApiClient);
          } catch (IOException e) {
            // something went wrong, discard the changes to the Drive file
            if (contents != null) contents.discard(googleApiClient);
          }

          if (contents != null) {
            String[] splitFilename = localFile.split("/");
            String filename = splitFilename[splitFilename.length - 1];
            MetadataChangeSet changeSet =
                new MetadataChangeSet.Builder()
                    .setTitle(filename)
                    .setMimeType(URLConnection.guessContentTypeFromName(filename))
                    .build();

            teamPhotosFolder.createFile(googleApiClient, changeSet, contents).await();
          }
        }

        Log.i(
            mActivity.getResources().getString(R.string.app_name),
            "Finished photo sync for team " + teamNumber);
        googleApiClient.disconnect();

        // hand the photos back to the PhotoRequester
        if (mRequester != null) {
          // first, get the list of image files
          listOfFiles = photosDir.listFiles();
          ArrayList<Bitmap> arrLocalBitmaps = new ArrayList<Bitmap>();
          for (File file : listOfFiles) {
            // make sure it's an image file
            Bitmap bitmap = BitmapFactory.decodeFile(file.getPath());
            if (bitmap != null) {
              arrLocalBitmaps.add(bitmap);
            }
            // else: if it's not a file, then what is it???? .... skip I guess
          }
          Bitmap[] bitmaps = new Bitmap[arrLocalBitmaps.size()];
          // TODO: commented out because it crashes the app with the error:
          // "Only the original thread that created a view hierarchy can touch its views."
          // This will need a re-jigging - maybe a loop in the PhotoRequester that checks for
          // updates every
          // few seconds and re-draws if there has been one.

          //                    mRequester.updatePhotos(arrLocalBitmaps.toArray(bitmaps));
        }
      }
    }