/**
   * Checks if the new name to set is valid in the file system
   *
   * <p>The only way to be sure is trying to create a file with that name. It's made in the temporal
   * directory for downloads, out of any account, and then removed.
   *
   * <p>IMPORTANT: The test must be made in the same file system where files are download. The
   * internal storage could be formatted with a different file system.
   *
   * <p>TODO move this method, and maybe FileDownload.get***Path(), to a class with utilities
   * specific for the interactions with the file system
   *
   * @return 'True' if a temporal file named with the name to set could be created in the file
   *     system where local files are stored.
   * @throws IOException When the temporal folder can not be created.
   */
  private boolean isValidNewName() throws IOException {
    // check tricky names
    if (mNewName == null
        || mNewName.length() <= 0
        || mNewName.contains(File.separator)
        || mNewName.contains("%")) {
      return false;
    }
    // create a test file
    String tmpFolderName = FileStorageUtils.getTemporalPath("");
    File testFile = new File(tmpFolderName + mNewName);
    File tmpFolder = testFile.getParentFile();
    tmpFolder.mkdirs();
    if (!tmpFolder.isDirectory()) {
      throw new IOException("Unexpected error: temporal directory could not be created");
    }
    try {
      testFile
          .createNewFile(); // return value is ignored; it could be 'false' because the file already
                            // existed, that doesn't invalidate the name
    } catch (IOException e) {
      Log_OC.i(TAG, "Test for validity of name " + mNewName + " in the file system failed");
      return false;
    }
    boolean result = (testFile.exists() && testFile.isFile());

    // cleaning ; result is ignored, since there is not much we could do in case of failure, but
    // repeat and repeat...
    testFile.delete();

    return result;
  }
  /** {@inheritDoc} */
  @Override
  public Bundle addAccount(
      AccountAuthenticatorResponse response,
      String accountType,
      String authTokenType,
      String[] requiredFeatures,
      Bundle options)
      throws NetworkErrorException {
    Log_OC.i(TAG, "Adding account with type " + accountType + " and auth token " + authTokenType);

    final Bundle bundle = new Bundle();

    AccountManager accountManager = AccountManager.get(mContext);
    Account[] accounts = accountManager.getAccountsByType(MainApp.getAccountType());

    if (mContext.getResources().getBoolean(R.bool.multiaccount_support) || accounts.length < 1) {
      try {
        validateAccountType(accountType);
      } catch (AuthenticatorException e) {
        Log_OC.e(TAG, "Failed to validate account type " + accountType + ": " + e.getMessage());
        e.printStackTrace();
        return e.getFailureBundle();
      }

      final Intent intent = new Intent(mContext, AuthenticatorActivity.class);
      intent.putExtra(AccountManager.KEY_ACCOUNT_AUTHENTICATOR_RESPONSE, response);
      intent.putExtra(KEY_AUTH_TOKEN_TYPE, authTokenType);
      intent.putExtra(KEY_REQUIRED_FEATURES, requiredFeatures);
      intent.putExtra(KEY_LOGIN_OPTIONS, options);
      intent.putExtra(AuthenticatorActivity.EXTRA_ACTION, AuthenticatorActivity.ACTION_CREATE);

      setIntentFlags(intent);

      bundle.putParcelable(AccountManager.KEY_INTENT, intent);

    } else {

      // Return an error
      bundle.putInt(AccountManager.KEY_ERROR_CODE, AccountManager.ERROR_CODE_UNSUPPORTED_OPERATION);
      final String message =
          String.format(
              mContext.getString(R.string.auth_unsupported_multiaccount),
              mContext.getString(R.string.app_name));
      bundle.putString(AccountManager.KEY_ERROR_MESSAGE, message);

      mHandler.post(
          new Runnable() {

            @Override
            public void run() {
              Toast.makeText(mContext, message, Toast.LENGTH_SHORT).show();
            }
          });
    }

    return bundle;
  }
示例#3
0
 /** Service initialization */
 @Override
 public void onCreate() {
   super.onCreate();
   Log_OC.i(TAG, "mPendingUploads size:" + mPendingUploads.size());
   mNotificationManager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
   HandlerThread thread =
       new HandlerThread("FileUploaderThread", Process.THREAD_PRIORITY_BACKGROUND);
   thread.start();
   mServiceLooper = thread.getLooper();
   mServiceHandler = new ServiceHandler(mServiceLooper, this);
   mBinder = new FileUploaderBinder();
 }
示例#4
0
 @Override
 protected void onCreate(Bundle savedInstanceState) {
   super.onCreate(savedInstanceState);
   getWindow().requestFeature(Window.FEATURE_NO_TITLE);
   mParents = new Stack<String>();
   mParents.add("");
   if (prepareStreamsToUpload()) {
     mAccountManager = (AccountManager) getSystemService(Context.ACCOUNT_SERVICE);
     Account[] accounts = mAccountManager.getAccountsByType(MainApp.getAccountType());
     if (accounts.length == 0) {
       Log_OC.i(TAG, "No ownCloud account is available");
       showDialog(DIALOG_NO_ACCOUNT);
     } else if (accounts.length > 1) {
       Log_OC.i(TAG, "More then one ownCloud is available");
       showDialog(DIALOG_MULTIPLE_ACCOUNT);
     } else {
       mAccount = accounts[0];
       mStorageManager = new FileDataStorageManager(mAccount, getContentResolver());
       populateDirectoryList();
     }
   } else {
     showDialog(DIALOG_NO_STREAM);
   }
 }
示例#5
0
 @Override
 protected void onActivityResult(int requestCode, int resultCode, Intent data) {
   super.onActivityResult(requestCode, resultCode, data);
   Log_OC.i(TAG, "result received. req: " + requestCode + " res: " + resultCode);
   if (requestCode == REQUEST_CODE_SETUP_ACCOUNT) {
     dismissDialog(DIALOG_NO_ACCOUNT);
     if (resultCode == RESULT_CANCELED) {
       finish();
     }
     Account[] accounts = mAccountManager.getAccountsByType(MainApp.getAuthTokenType());
     if (accounts.length == 0) {
       showDialog(DIALOG_NO_ACCOUNT);
     } else {
       // there is no need for checking for is there more then one
       // account at this point
       // since account setup can set only one account at time
       mAccount = accounts[0];
       populateDirectoryList();
     }
   }
 }
示例#6
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);
    }
  }
示例#7
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;
  }