/** * 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); }
/** * 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); }
/** * 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); } }
/** * 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); } }