Beispiel #1
0
  /**
   * Creates a status notification to show the upload progress
   *
   * @param upload Upload operation starting.
   */
  @SuppressWarnings("deprecation")
  private void notifyUploadStart(UploadFileOperation upload) {
    // / create status notification with a progress bar
    mLastPercent = 0;
    mNotification =
        new Notification(
            DisplayUtils.getSeasonalIconId(),
            getString(R.string.uploader_upload_in_progress_ticker),
            System.currentTimeMillis());
    mNotification.flags |= Notification.FLAG_ONGOING_EVENT;
    mDefaultNotificationContentView = mNotification.contentView;
    mNotification.contentView =
        new RemoteViews(getApplicationContext().getPackageName(), R.layout.progressbar_layout);
    mNotification.contentView.setProgressBar(R.id.status_progress, 100, 0, false);
    mNotification.contentView.setTextViewText(
        R.id.status_text,
        String.format(
            getString(R.string.uploader_upload_in_progress_content), 0, upload.getFileName()));
    mNotification.contentView.setImageViewResource(
        R.id.status_icon, DisplayUtils.getSeasonalIconId());

    /// includes a pending intent in the notification showing the details view of the file
    Intent showDetailsIntent = new Intent(this, FileDisplayActivity.class);
    showDetailsIntent.putExtra(FileActivity.EXTRA_FILE, upload.getFile());
    showDetailsIntent.putExtra(FileActivity.EXTRA_ACCOUNT, upload.getAccount());
    showDetailsIntent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
    mNotification.contentIntent =
        PendingIntent.getActivity(
            getApplicationContext(), (int) System.currentTimeMillis(), showDetailsIntent, 0);

    mNotificationManager.notify(R.string.uploader_upload_in_progress_ticker, mNotification);
  }
Beispiel #2
0
  /**
   * Saves a OC File after a successful upload.
   *
   * <p>A PROPFIND is necessary to keep the props in the local database synchronized with the
   * server, specially the modification time and Etag (where available)
   *
   * <p>TODO refactor this ugly thing
   */
  private void saveUploadedFile() {
    OCFile file = mCurrentUpload.getFile();
    if (file.fileExists()) {
      file = mStorageManager.getFileById(file.getFileId());
    }
    long syncDate = System.currentTimeMillis();
    file.setLastSyncDateForData(syncDate);

    // new PROPFIND to keep data consistent with server
    // in theory, should return the same we already have
    ReadRemoteFileOperation operation = new ReadRemoteFileOperation(mCurrentUpload.getRemotePath());
    RemoteOperationResult result = operation.execute(mUploadClient);
    if (result.isSuccess()) {
      updateOCFile(file, (RemoteFile) result.getData().get(0));
      file.setLastSyncDateForProperties(syncDate);
    }

    // / maybe this would be better as part of UploadFileOperation... or
    // maybe all this method
    if (mCurrentUpload.wasRenamed()) {
      OCFile oldFile = mCurrentUpload.getOldFile();
      if (oldFile.fileExists()) {
        oldFile.setStoragePath(null);
        mStorageManager.saveFile(oldFile);
      } // else: it was just an automatic renaming due to a name
      // coincidence; nothing else is needed, the storagePath is right
      // in the instance returned by mCurrentUpload.getFile()
    }

    mStorageManager.saveFile(file);
  }
Beispiel #3
0
 /**
  * Cancels a pending or current upload of a remote file.
  *
  * @param account Owncloud account where the remote file will be stored.
  * @param file A file in the queue of pending uploads
  */
 public void cancel(Account account, OCFile file) {
   UploadFileOperation upload = null;
   synchronized (mPendingUploads) {
     upload = mPendingUploads.remove(buildRemoteName(account, file));
   }
   if (upload != null) {
     upload.cancel();
   }
 }
Beispiel #4
0
 /**
  * Sends a broadcast in order to the interested activities can update their view
  *
  * @param upload Finished upload operation
  * @param uploadResult Result of the upload operation
  */
 private void sendFinalBroadcast(UploadFileOperation upload, RemoteOperationResult uploadResult) {
   Intent end = new Intent(getUploadFinishMessage());
   end.putExtra(EXTRA_REMOTE_PATH, upload.getRemotePath()); // real remote
   // path, after
   // possible
   // automatic
   // renaming
   if (upload.wasRenamed()) {
     end.putExtra(EXTRA_OLD_REMOTE_PATH, upload.getOldFile().getRemotePath());
   }
   end.putExtra(EXTRA_OLD_FILE_PATH, upload.getOriginalStoragePath());
   end.putExtra(ACCOUNT_NAME, upload.getAccount().name);
   end.putExtra(EXTRA_UPLOAD_RESULT, uploadResult.isSuccess());
   sendStickyBroadcast(end);
 }
Beispiel #5
0
 /**
  * Checks the existence of the folder where the current file will be uploaded both in the remote
  * server and in the local database.
  *
  * <p>If the upload is set to enforce the creation of the folder, the method tries to create it
  * both remote and locally.
  *
  * @param pathToGrant Full remote path whose existence will be granted.
  * @return An {@link OCFile} instance corresponding to the folder where the file will be uploaded.
  */
 private RemoteOperationResult grantFolderExistence(String pathToGrant) {
   RemoteOperation operation = new ExistenceCheckRemoteOperation(pathToGrant, this, false);
   RemoteOperationResult result = operation.execute(mUploadClient);
   if (!result.isSuccess()
       && result.getCode() == ResultCode.FILE_NOT_FOUND
       && mCurrentUpload.isRemoteFolderToBeCreated()) {
     operation = new CreateFolderOperation(pathToGrant, true, mStorageManager);
     result = operation.execute(mUploadClient);
   }
   if (result.isSuccess()) {
     OCFile parentDir = mStorageManager.getFileByPath(pathToGrant);
     if (parentDir == null) {
       parentDir = createLocalFolder(pathToGrant);
     }
     if (parentDir != null) {
       result = new RemoteOperationResult(ResultCode.OK);
     } else {
       result = new RemoteOperationResult(ResultCode.UNKNOWN_ERROR);
     }
   }
   return result;
 }
Beispiel #6
0
  /**
   * Updates the status notification with the result of an upload operation.
   *
   * @param uploadResult Result of the upload operation.
   * @param upload Finished upload operation
   */
  private void notifyUploadResult(RemoteOperationResult uploadResult, UploadFileOperation upload) {
    Log_OC.d(TAG, "NotifyUploadResult with resultCode: " + uploadResult.getCode());
    if (uploadResult.isCancelled()) {
      // / cancelled operation -> silent removal of progress notification
      mNotificationManager.cancel(R.string.uploader_upload_in_progress_ticker);

    } else if (uploadResult.isSuccess()) {
      // / success -> silent update of progress notification to success
      // message
      mNotification.flags ^= Notification.FLAG_ONGOING_EVENT; // remove
      // the
      // ongoing
      // flag
      mNotification.flags |= Notification.FLAG_AUTO_CANCEL;
      mNotification.contentView = mDefaultNotificationContentView;

      /// includes a pending intent in the notification showing the details view of the file
      Intent showDetailsIntent = null;
      if (PreviewImageFragment.canBePreviewed(upload.getFile())) {
        showDetailsIntent = new Intent(this, PreviewImageActivity.class);
      } else {
        showDetailsIntent = new Intent(this, FileDisplayActivity.class);
      }
      showDetailsIntent.putExtra(FileActivity.EXTRA_FILE, upload.getFile());
      showDetailsIntent.putExtra(FileActivity.EXTRA_ACCOUNT, upload.getAccount());
      showDetailsIntent.putExtra(FileActivity.EXTRA_FROM_NOTIFICATION, true);
      showDetailsIntent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
      mNotification.contentIntent =
          PendingIntent.getActivity(
              getApplicationContext(), (int) System.currentTimeMillis(), showDetailsIntent, 0);

      mNotification.setLatestEventInfo(
          getApplicationContext(),
          getString(R.string.uploader_upload_succeeded_ticker),
          String.format(
              getString(R.string.uploader_upload_succeeded_content_single), upload.getFileName()),
          mNotification.contentIntent);

      mNotificationManager.notify(
          R.string.uploader_upload_in_progress_ticker, mNotification); // NOT
      // AN
      DbHandler db = new DbHandler(this.getBaseContext());
      db.removeIUPendingFile(mCurrentUpload.getOriginalStoragePath());
      db.close();

    } else {

      // / fail -> explicit failure notification
      mNotificationManager.cancel(R.string.uploader_upload_in_progress_ticker);
      Notification finalNotification =
          new Notification(
              DisplayUtils.getSeasonalIconId(),
              getString(R.string.uploader_upload_failed_ticker),
              System.currentTimeMillis());
      finalNotification.flags |= Notification.FLAG_AUTO_CANCEL;
      String content = null;

      boolean needsToUpdateCredentials =
          (uploadResult.getCode() == ResultCode.UNAUTHORIZED
              ||
              // (uploadResult.isTemporalRedirection() && uploadResult.isIdPRedirection() &&
              (uploadResult.isIdPRedirection() && mUploadClient.getCredentials() == null));
      // MainApp.getAuthTokenTypeSamlSessionCookie().equals(mUploadClient.getAuthTokenType())));
      if (needsToUpdateCredentials) {
        // let the user update credentials with one click
        Intent updateAccountCredentials = new Intent(this, AuthenticatorActivity.class);
        updateAccountCredentials.putExtra(AuthenticatorActivity.EXTRA_ACCOUNT, upload.getAccount());
        updateAccountCredentials.putExtra(AuthenticatorActivity.EXTRA_ENFORCED_UPDATE, true);
        updateAccountCredentials.putExtra(
            AuthenticatorActivity.EXTRA_ACTION, AuthenticatorActivity.ACTION_UPDATE_TOKEN);
        updateAccountCredentials.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
        updateAccountCredentials.addFlags(Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
        updateAccountCredentials.addFlags(Intent.FLAG_FROM_BACKGROUND);
        finalNotification.contentIntent =
            PendingIntent.getActivity(
                this,
                (int) System.currentTimeMillis(),
                updateAccountCredentials,
                PendingIntent.FLAG_ONE_SHOT);
        content =
            String.format(
                getString(R.string.uploader_upload_failed_content_single), upload.getFileName());
        finalNotification.setLatestEventInfo(
            getApplicationContext(),
            getString(R.string.uploader_upload_failed_ticker),
            content,
            finalNotification.contentIntent);
        mUploadClient =
            null; // grant that future retries on the same account will get the fresh credentials
      } else {
        // TODO put something smart in the contentIntent below
        //    finalNotification.contentIntent = PendingIntent.getActivity(getApplicationContext(),
        // (int)System.currentTimeMillis(), new Intent(), 0);
        // }

        if (uploadResult.getCode() == ResultCode.LOCAL_STORAGE_FULL
            || uploadResult.getCode() == ResultCode.LOCAL_STORAGE_NOT_COPIED) {
          // TODO we need a class to provide error messages for the users
          // from a RemoteOperationResult and a RemoteOperation
          content =
              String.format(
                  getString(R.string.error__upload__local_file_not_copied),
                  upload.getFileName(),
                  getString(R.string.app_name));
        } else if (uploadResult.getCode() == ResultCode.QUOTA_EXCEEDED) {
          content = getString(R.string.failed_upload_quota_exceeded_text);
        } else {
          content =
              String.format(
                  getString(R.string.uploader_upload_failed_content_single), upload.getFileName());
        }

        // we add only for instant-uploads the InstantUploadActivity and the
        // db entry
        Intent detailUploadIntent = null;
        if (upload.isInstant() && InstantUploadActivity.IS_ENABLED) {
          detailUploadIntent = new Intent(this, InstantUploadActivity.class);
          detailUploadIntent.putExtra(FileUploader.KEY_ACCOUNT, upload.getAccount());
        } else {
          detailUploadIntent = new Intent(this, FailedUploadActivity.class);
          detailUploadIntent.putExtra(FailedUploadActivity.MESSAGE, content);
        }
        finalNotification.contentIntent =
            PendingIntent.getActivity(
                getApplicationContext(),
                (int) System.currentTimeMillis(),
                detailUploadIntent,
                PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_ONE_SHOT);

        if (upload.isInstant()) {
          DbHandler db = null;
          try {
            db = new DbHandler(this.getBaseContext());
            String message = uploadResult.getLogMessage() + " errorCode: " + uploadResult.getCode();
            Log_OC.e(TAG, message + " Http-Code: " + uploadResult.getHttpCode());
            if (uploadResult.getCode() == ResultCode.QUOTA_EXCEEDED) {
              message = getString(R.string.failed_upload_quota_exceeded_text);
              if (db.updateFileState(
                      upload.getOriginalStoragePath(),
                      DbHandler.UPLOAD_STATUS_UPLOAD_FAILED,
                      message)
                  == 0) {
                db.putFileForLater(
                    upload.getOriginalStoragePath(), upload.getAccount().name, message);
              }
            }
          } finally {
            if (db != null) {
              db.close();
            }
          }
        }
      }
      finalNotification.setLatestEventInfo(
          getApplicationContext(),
          getString(R.string.uploader_upload_failed_ticker),
          content,
          finalNotification.contentIntent);

      mNotificationManager.notify(R.string.uploader_upload_failed_ticker, finalNotification);
    }
  }
Beispiel #7
0
  /**
   * Core upload method: sends the file(s) to upload
   *
   * @param uploadKey Key to access the upload to perform, contained in mPendingUploads
   */
  public void uploadFile(String uploadKey) {

    synchronized (mPendingUploads) {
      mCurrentUpload = mPendingUploads.get(uploadKey);
    }

    if (mCurrentUpload != null) {

      notifyUploadStart(mCurrentUpload);

      RemoteOperationResult uploadResult = null, grantResult = null;

      try {
        /// prepare client object to send requests to the ownCloud server
        if (mUploadClient == null || !mLastAccount.equals(mCurrentUpload.getAccount())) {
          mLastAccount = mCurrentUpload.getAccount();
          mStorageManager = new FileDataStorageManager(mLastAccount, getContentResolver());
          mUploadClient =
              OwnCloudClientFactory.createOwnCloudClient(mLastAccount, getApplicationContext());
        }

        /// check the existence of the parent folder for the file to upload
        String remoteParentPath = new File(mCurrentUpload.getRemotePath()).getParent();
        remoteParentPath =
            remoteParentPath.endsWith(OCFile.PATH_SEPARATOR)
                ? remoteParentPath
                : remoteParentPath + OCFile.PATH_SEPARATOR;
        grantResult = grantFolderExistence(remoteParentPath);

        /// perform the upload
        if (grantResult.isSuccess()) {
          OCFile parent = mStorageManager.getFileByPath(remoteParentPath);
          mCurrentUpload.getFile().setParentId(parent.getFileId());
          uploadResult = mCurrentUpload.execute(mUploadClient);
          if (uploadResult.isSuccess()) {
            saveUploadedFile();
          }
        } else {
          uploadResult = grantResult;
        }

      } catch (AccountsException e) {
        Log_OC.e(TAG, "Error while trying to get autorization for " + mLastAccount.name, e);
        uploadResult = new RemoteOperationResult(e);

      } catch (IOException e) {
        Log_OC.e(TAG, "Error while trying to get autorization for " + mLastAccount.name, e);
        uploadResult = new RemoteOperationResult(e);

      } finally {
        synchronized (mPendingUploads) {
          mPendingUploads.remove(uploadKey);
          Log_OC.i(TAG, "Remove CurrentUploadItem from pending upload Item Map.");
        }
        if (uploadResult.isException()) {
          // enforce the creation of a new client object for next uploads; this grant that a new
          // socket will
          // be created in the future if the current exception is due to an abrupt lose of network
          // connection
          mUploadClient = null;
        }
      }

      /// notify result

      notifyUploadResult(uploadResult, mCurrentUpload);
      sendFinalBroadcast(mCurrentUpload, uploadResult);
    }
  }
Beispiel #8
0
  /**
   * Entry point to add one or several files to the queue of uploads.
   *
   * <p>New uploads are added calling to startService(), resulting in a call to this method. This
   * ensures the service will keep on working although the caller activity goes away.
   */
  @Override
  public int onStartCommand(Intent intent, int flags, int startId) {
    if (!intent.hasExtra(KEY_ACCOUNT)
        || !intent.hasExtra(KEY_UPLOAD_TYPE)
        || !(intent.hasExtra(KEY_LOCAL_FILE) || intent.hasExtra(KEY_FILE))) {
      Log_OC.e(TAG, "Not enough information provided in intent");
      return Service.START_NOT_STICKY;
    }
    int uploadType = intent.getIntExtra(KEY_UPLOAD_TYPE, -1);
    if (uploadType == -1) {
      Log_OC.e(TAG, "Incorrect upload type provided");
      return Service.START_NOT_STICKY;
    }
    Account account = intent.getParcelableExtra(KEY_ACCOUNT);

    String[] localPaths = null, remotePaths = null, mimeTypes = null;
    OCFile[] files = null;
    if (uploadType == UPLOAD_SINGLE_FILE) {

      if (intent.hasExtra(KEY_FILE)) {
        files = new OCFile[] {intent.getParcelableExtra(KEY_FILE)};

      } else {
        localPaths = new String[] {intent.getStringExtra(KEY_LOCAL_FILE)};
        remotePaths = new String[] {intent.getStringExtra(KEY_REMOTE_FILE)};
        mimeTypes = new String[] {intent.getStringExtra(KEY_MIME_TYPE)};
      }

    } else { // mUploadType == UPLOAD_MULTIPLE_FILES

      if (intent.hasExtra(KEY_FILE)) {
        files = (OCFile[]) intent.getParcelableArrayExtra(KEY_FILE); // TODO
        // will
        // this
        // casting
        // work
        // fine?

      } else {
        localPaths = intent.getStringArrayExtra(KEY_LOCAL_FILE);
        remotePaths = intent.getStringArrayExtra(KEY_REMOTE_FILE);
        mimeTypes = intent.getStringArrayExtra(KEY_MIME_TYPE);
      }
    }

    FileDataStorageManager storageManager =
        new FileDataStorageManager(account, getContentResolver());

    boolean forceOverwrite = intent.getBooleanExtra(KEY_FORCE_OVERWRITE, false);
    boolean isInstant = intent.getBooleanExtra(KEY_INSTANT_UPLOAD, false);
    int localAction = intent.getIntExtra(KEY_LOCAL_BEHAVIOUR, LOCAL_BEHAVIOUR_COPY);

    if (intent.hasExtra(KEY_FILE) && files == null) {
      Log_OC.e(TAG, "Incorrect array for OCFiles provided in upload intent");
      return Service.START_NOT_STICKY;

    } else if (!intent.hasExtra(KEY_FILE)) {
      if (localPaths == null) {
        Log_OC.e(TAG, "Incorrect array for local paths provided in upload intent");
        return Service.START_NOT_STICKY;
      }
      if (remotePaths == null) {
        Log_OC.e(TAG, "Incorrect array for remote paths provided in upload intent");
        return Service.START_NOT_STICKY;
      }
      if (localPaths.length != remotePaths.length) {
        Log_OC.e(TAG, "Different number of remote paths and local paths!");
        return Service.START_NOT_STICKY;
      }

      files = new OCFile[localPaths.length];
      for (int i = 0; i < localPaths.length; i++) {
        files[i] =
            obtainNewOCFileToUpload(
                remotePaths[i],
                localPaths[i],
                ((mimeTypes != null) ? mimeTypes[i] : (String) null),
                storageManager);
        if (files[i] == null) {
          // TODO @andomaex add failure Notification
          return Service.START_NOT_STICKY;
        }
      }
    }

    AccountManager aMgr = AccountManager.get(this);
    String version = aMgr.getUserData(account, OwnCloudAccount.Constants.KEY_OC_VERSION);
    String versionString =
        aMgr.getUserData(account, OwnCloudAccount.Constants.KEY_OC_VERSION_STRING);
    OwnCloudVersion ocv = new OwnCloudVersion(version, versionString);
    boolean chunked = FileUploader.chunkedUploadIsSupported(ocv);
    AbstractList<String> requestedUploads = new Vector<String>();
    String uploadKey = null;
    UploadFileOperation newUpload = null;
    try {
      for (int i = 0; i < files.length; i++) {
        uploadKey = buildRemoteName(account, files[i].getRemotePath());
        newUpload =
            new UploadFileOperation(
                account,
                files[i],
                chunked,
                isInstant,
                forceOverwrite,
                localAction,
                getApplicationContext());
        if (isInstant) {
          newUpload.setRemoteFolderToBeCreated();
        }
        mPendingUploads.putIfAbsent(
            uploadKey, newUpload); // Grants that the file only upload once time

        newUpload.addDatatransferProgressListener(this);
        newUpload.addDatatransferProgressListener((FileUploaderBinder) mBinder);
        requestedUploads.add(uploadKey);
      }

    } catch (IllegalArgumentException e) {
      Log_OC.e(TAG, "Not enough information provided in intent: " + e.getMessage());
      return START_NOT_STICKY;

    } catch (IllegalStateException e) {
      Log_OC.e(TAG, "Bad information provided in intent: " + e.getMessage());
      return START_NOT_STICKY;

    } catch (Exception e) {
      Log_OC.e(TAG, "Unexpected exception while processing upload intent", e);
      return START_NOT_STICKY;
    }

    if (requestedUploads.size() > 0) {
      Message msg = mServiceHandler.obtainMessage();
      msg.arg1 = startId;
      msg.obj = requestedUploads;
      mServiceHandler.sendMessage(msg);
    }
    Log_OC.i(TAG, "mPendingUploads size:" + mPendingUploads.size());
    return Service.START_NOT_STICKY;
  }