/** {@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; }
private OCFile obtainNewOCFileToUpload( String remotePath, String localPath, String mimeType, FileDataStorageManager storageManager) { OCFile newFile = new OCFile(remotePath); newFile.setStoragePath(localPath); newFile.setLastSyncDateForProperties(0); newFile.setLastSyncDateForData(0); // size if (localPath != null && localPath.length() > 0) { File localFile = new File(localPath); newFile.setFileLength(localFile.length()); newFile.setLastSyncDateForData(localFile.lastModified()); } // don't worry about not assigning size, the problems with localPath // are checked when the UploadFileOperation instance is created // MIME type if (mimeType == null || mimeType.length() <= 0) { try { mimeType = MimeTypeMap.getSingleton() .getMimeTypeFromExtension(remotePath.substring(remotePath.lastIndexOf('.') + 1)); } catch (IndexOutOfBoundsException e) { Log_OC.e(TAG, "Trying to find out MIME type of a file without extension: " + remotePath); } } if (mimeType == null) { mimeType = "application/octet-stream"; } newFile.setMimetype(mimeType); return newFile; }
private void populateDirectoryList() { setContentView(R.layout.uploader_layout); String full_path = ""; for (String a : mParents) full_path += a + "/"; Log_OC.d(TAG, "Populating view with content of : " + full_path); mFile = mStorageManager.getFileByPath(full_path); if (mFile != null) { Vector<OCFile> files = mStorageManager.getFolderContent(mFile); List<HashMap<String, Object>> data = new LinkedList<HashMap<String, Object>>(); for (OCFile f : files) { HashMap<String, Object> h = new HashMap<String, Object>(); if (f.isFolder()) { h.put("dirname", f.getFileName()); data.add(h); } } SimpleAdapter sa = new SimpleAdapter( this, data, R.layout.uploader_list_item_layout, new String[] {"dirname"}, new int[] {R.id.textView1}); setListAdapter(sa); Button btn = (Button) findViewById(R.id.uploader_choose_folder); btn.setOnClickListener(this); getListView().setOnItemClickListener(this); } }
/** * 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; }
private void onCreateRemoteFolderOperationFinish( CreateRemoteFolderOperation operation, RemoteOperationResult result) { if (result.isSuccess()) { saveFolderInDB(); } else { Log_OC.e(TAG, mRemotePath + "hasn't been created"); } }
/** * Entry point to add a new operation to the queue of operations. * * <p>New operations 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. * * <p>IMPORTANT: the only operations performed here right now is {@link GetSharedFilesOperation}. * The class is taking advantage of it due to time constraints. */ @Override public int onStartCommand(Intent intent, int flags, int startId) { if (!intent.hasExtra(EXTRA_ACCOUNT) && !intent.hasExtra(EXTRA_SERVER_URL)) { Log_OC.e(TAG, "Not enough information provided in intent"); return START_NOT_STICKY; } try { Account account = intent.getParcelableExtra(EXTRA_ACCOUNT); String serverUrl = intent.getStringExtra(EXTRA_SERVER_URL); Target target = new Target(account, (serverUrl == null) ? null : Uri.parse(serverUrl)); RemoteOperation operation = null; String action = intent.getAction(); if (action.equals(ACTION_CREATE_SHARE)) { // Create Share String remotePath = intent.getStringExtra(EXTRA_REMOTE_PATH); Intent sendIntent = intent.getParcelableExtra(EXTRA_SEND_INTENT); if (remotePath.length() > 0) { operation = new CreateShareOperation( remotePath, ShareType.PUBLIC_LINK, "", false, "", 1, sendIntent); } } else if (action.equals(ACTION_UNSHARE)) { // Unshare file String remotePath = intent.getStringExtra(EXTRA_REMOTE_PATH); if (remotePath.length() > 0) { operation = new UnshareLinkOperation(remotePath, this.getApplicationContext()); } } else { // nothing we are going to handle return START_NOT_STICKY; } mPendingOperations.add(new Pair<Target, RemoteOperation>(target, operation)); // sendBroadcastNewOperation(target, operation); Message msg = mServiceHandler.obtainMessage(); msg.arg1 = startId; mServiceHandler.sendMessage(msg); } catch (IllegalArgumentException e) { Log_OC.e(TAG, "Bad information provided in intent: " + e.getMessage()); return START_NOT_STICKY; } return START_NOT_STICKY; }
/** Save new directory in local database */ public void saveFolderInDB() { OCFile newDir = new OCFile(mRemotePath); newDir.setMimetype("DIR"); long parentId = mStorageManager.getFileByPath(FileStorageUtils.getParentPath(mRemotePath)).getFileId(); newDir.setParentId(parentId); newDir.setModificationTimestamp(System.currentTimeMillis()); mStorageManager.saveFile(newDir); Log_OC.d(TAG, "Create directory " + mRemotePath + " in Database"); }
/** 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(); }
@Override protected RemoteOperationResult run(OwnCloudClient client) { CreateRemoteFolderOperation operation = new CreateRemoteFolderOperation(mRemotePath, mCreateFullPath); RemoteOperationResult result = operation.execute(client); if (result.isSuccess()) { saveFolderInDB(); } else { Log_OC.e(TAG, mRemotePath + "hasn't been created"); } return result; }
/** * Performs the rename operation. * * @param client Client object to communicate with the remote ownCloud server. */ @Override protected RemoteOperationResult run(OwnCloudClient client) { RemoteOperationResult result = null; // check if the new name is valid in the local file system try { if (!isValidNewName()) { return new RemoteOperationResult(ResultCode.INVALID_LOCAL_FILE_NAME); } String parent = (new File(mFile.getRemotePath())).getParent(); parent = (parent.endsWith(OCFile.PATH_SEPARATOR)) ? parent : parent + OCFile.PATH_SEPARATOR; mNewRemotePath = parent + mNewName; if (mFile.isFolder()) { mNewRemotePath += OCFile.PATH_SEPARATOR; } // ckeck local overwrite if (mStorageManager.getFileByPath(mNewRemotePath) != null) { return new RemoteOperationResult(ResultCode.INVALID_OVERWRITE); } RenameRemoteFileOperation operation = new RenameRemoteFileOperation( mFile.getFileName(), mFile.getRemotePath(), mNewName, mFile.isFolder()); result = operation.execute(client); if (result.isSuccess()) { if (mFile.isFolder()) { saveLocalDirectory(); } else { saveLocalFile(); } } } catch (IOException e) { Log_OC.e( TAG, "Rename " + mFile.getRemotePath() + " to " + ((mNewRemotePath == null) ? mNewName : mNewRemotePath) + ": " + ((result != null) ? result.getLogMessage() : ""), e); } return result; }
@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); } }
@Override public void onItemClick(AdapterView<?> parent, View view, int position, long id) { // click on folder in the list Log_OC.d(TAG, "on item click"); Vector<OCFile> tmpfiles = mStorageManager.getFolderContent(mFile); if (tmpfiles.size() <= 0) return; // filter on dirtype Vector<OCFile> files = new Vector<OCFile>(); for (OCFile f : tmpfiles) if (f.isFolder()) files.add(f); if (files.size() < position) { throw new IndexOutOfBoundsException("Incorrect item selected"); } mParents.push(files.get(position).getFileName()); populateDirectoryList(); }
@Override public void onClick(View v) { // click on button switch (v.getId()) { case R.id.uploader_choose_folder: mUploadPath = ""; // first element in mParents is root dir, represented by ""; init mUploadPath with // "/" results in a "//" prefix for (String p : mParents) mUploadPath += p + OCFile.PATH_SEPARATOR; Log_OC.d(TAG, "Uploading file to dir " + mUploadPath); uploadFiles(); break; default: throw new IllegalArgumentException("Wrong element clicked"); } }
/** {@inheritDoc} */ @Override public Bundle getAuthToken( AccountAuthenticatorResponse response, Account account, String authTokenType, Bundle options) throws NetworkErrorException { /// validate parameters try { validateAccountType(account.type); validateAuthTokenType(authTokenType); } catch (AuthenticatorException e) { Log_OC.e(TAG, "Failed to validate account type " + account.type + ": " + e.getMessage()); e.printStackTrace(); return e.getFailureBundle(); } /// check if required token is stored final AccountManager am = AccountManager.get(mContext); String accessToken; if (authTokenType.equals(AccountTypeUtils.getAuthTokenTypePass(MainApp.getAccountType()))) { accessToken = am.getPassword(account); } else { accessToken = am.peekAuthToken(account, authTokenType); } if (accessToken != null) { final Bundle result = new Bundle(); result.putString(AccountManager.KEY_ACCOUNT_NAME, account.name); result.putString(AccountManager.KEY_ACCOUNT_TYPE, MainApp.getAccountType()); result.putString(AccountManager.KEY_AUTHTOKEN, accessToken); return result; } /// if not stored, return Intent to access the AuthenticatorActivity and UPDATE the token for // the account 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_LOGIN_OPTIONS, options); intent.putExtra(AuthenticatorActivity.EXTRA_ACCOUNT, account); intent.putExtra(AuthenticatorActivity.EXTRA_ENFORCED_UPDATE, true); intent.putExtra(AuthenticatorActivity.EXTRA_ACTION, AuthenticatorActivity.ACTION_UPDATE_TOKEN); final Bundle bundle = new Bundle(); bundle.putParcelable(AccountManager.KEY_INTENT, intent); return bundle; }
@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(); } } }
/** {@inheritDoc} */ @Override public Bundle confirmCredentials( AccountAuthenticatorResponse response, Account account, Bundle options) throws NetworkErrorException { try { validateAccountType(account.type); } catch (AuthenticatorException e) { Log_OC.e(TAG, "Failed to validate account type " + account.type + ": " + e.getMessage()); e.printStackTrace(); return e.getFailureBundle(); } Intent intent = new Intent(mContext, AuthenticatorActivity.class); intent.putExtra(AccountManager.KEY_ACCOUNT_AUTHENTICATOR_RESPONSE, response); intent.putExtra(KEY_ACCOUNT, account); intent.putExtra(KEY_LOGIN_OPTIONS, options); setIntentFlags(intent); Bundle resultBundle = new Bundle(); resultBundle.putParcelable(AccountManager.KEY_INTENT, intent); return resultBundle; }
/** * 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); } }
/** * 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; }
/** * 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); } }
/** Performs the next operation in the queue */ private void nextOperation() { Pair<Target, RemoteOperation> next = null; synchronized (mPendingOperations) { next = mPendingOperations.peek(); } if (next != null) { mCurrentOperation = next.second; RemoteOperationResult result = null; try { /// prepare client object to send the request to the ownCloud server if (mLastTarget == null || !mLastTarget.equals(next.first)) { mLastTarget = next.first; if (mLastTarget.mAccount != null) { mOwnCloudClient = OwnCloudClientFactory.createOwnCloudClient( mLastTarget.mAccount, getApplicationContext()); mStorageManager = new FileDataStorageManager(mLastTarget.mAccount, getContentResolver()); } else { mOwnCloudClient = OwnCloudClientFactory.createOwnCloudClient( mLastTarget.mServerUrl, getApplicationContext(), true); // this is not good enough mStorageManager = null; } } /// perform the operation if (mCurrentOperation instanceof SyncOperation) { result = ((SyncOperation) mCurrentOperation).execute(mOwnCloudClient, mStorageManager); } else { result = mCurrentOperation.execute(mOwnCloudClient); } } catch (AccountsException e) { if (mLastTarget.mAccount == null) { Log_OC.e(TAG, "Error while trying to get autorization for a NULL account", e); } else { Log_OC.e( TAG, "Error while trying to get autorization for " + mLastTarget.mAccount.name, e); } result = new RemoteOperationResult(e); } catch (IOException e) { if (mLastTarget.mAccount == null) { Log_OC.e(TAG, "Error while trying to get autorization for a NULL account", e); } else { Log_OC.e( TAG, "Error while trying to get autorization for " + mLastTarget.mAccount.name, e); } result = new RemoteOperationResult(e); } catch (Exception e) { if (mLastTarget.mAccount == null) { Log_OC.e(TAG, "Unexpected error for a NULL account", e); } else { Log_OC.e(TAG, "Unexpected error for " + mLastTarget.mAccount.name, e); } result = new RemoteOperationResult(e); } finally { synchronized (mPendingOperations) { mPendingOperations.poll(); } } // sendBroadcastOperationFinished(mLastTarget, mCurrentOperation, result); callbackOperationListeners(mLastTarget, mCurrentOperation, result); } }