I'm trying to download a list of RemoteFiles in Android using ownCloud. I can download the files perfectly fine but I'd like to notify the user when a file finishes. I'm downloading an entire directory:
#Override
public void onRemoteOperationFinish(RemoteOperation operation, RemoteOperationResult result) {
if (operation instanceof ReadRemoteFolderOperation) {
if (result.isSuccess()) {
Toast.makeText(this, "Finished reading folder", Toast.LENGTH_SHORT).show();
for (Object o : result.getData()) {
RemoteFile remoteFile = (RemoteFile) o;
String remotePath = remoteFile.getRemotePath();
File targetDirectory = new File(Environment.getExternalStorageDirectory().getAbsolutePath() +
"/owncloud_download");
downloadHelper.downloadFile(remoteFile, targetDirectory);
}
}
}
if (operation instanceof DownloadRemoteFileOperation) {
if (result.isSuccess()) {
// Notify the user here that the file finished
}
}
}
I've looked at the ownCloud library source but can't seem to find what a DownloadRemoteFileOperation returns as a result other than a boolean indicating success and an HTTP status code. I thought it might be in result.getLogMessage() but that just gives me an HTTP 200 status. How can I get the name of a file that's finished?
Edit: I also looked at result.getData() but that's null in a DownloadRemoteFileOperation.
Here's my workaround for the time being. I didn't want to modify the ownCloud library source (again) so instead I just do a check in onTransferProgress like so:
#Override
public void onTransferProgress(long rate, long transferred, long total, String fileName) {
if (transferred == total) {
runOnUiThread(new Runnable() {
// do the update here, file name is available
}
}
}
Here's another option. I needed the file being uploaded if the upload failed so I modified the ownCloud library source. This way I could return file names in the RemoteOperationResult.
RemoteOperationResult.java:
private String fileName;
public String getFileName() {
return fileName;
}
public void setFileName(String name) {
fileName = name;
}
DownloadRemoteFileOperation.java
#Override
protected RemoteOperationResult run(OwnCloudClient client) {
RemoteOperationResult result = null;
/// download will be performed to a temporal file, then moved to the final location
File tmpFile = new File(getTmpPath());
/// perform the download
try {
tmpFile.getParentFile().mkdirs();
int status = downloadFile(client, tmpFile);
result = new RemoteOperationResult(isSuccess(status), status,
(mGet != null ? mGet.getResponseHeaders() : null));
Log_OC.i(TAG, "Download of " + mRemotePath + " to " + getTmpPath() + ": " +
result.getLogMessage());
} catch (Exception e) {
result = new RemoteOperationResult(e);
Log_OC.e(TAG, "Download of " + mRemotePath + " to " + getTmpPath() + ": " +
result.getLogMessage(), e);
}
// Added this line
result.setFileName(mRemotePath);
return result;
}
UploadRemoteFileOperation.java:
#Override
protected RemoteOperationResult run(OwnCloudClient client) {
RemoteOperationResult result = null;
try {
// / perform the upload
synchronized (mCancellationRequested) {
if (mCancellationRequested.get()) {
throw new OperationCancelledException();
} else {
mPutMethod = new PutMethod(client.getWebdavUri() +
WebdavUtils.encodePath(mRemotePath));
}
}
int status = uploadFile(client);
if (mForbiddenCharsInServer){
result = new RemoteOperationResult(
RemoteOperationResult.ResultCode.INVALID_CHARACTER_DETECT_IN_SERVER);
} else {
result = new RemoteOperationResult(isSuccess(status), status,
(mPutMethod != null ? mPutMethod.getResponseHeaders() : null));
}
} catch (Exception e) {
// TODO something cleaner with cancellations
if (mCancellationRequested.get()) {
result = new RemoteOperationResult(new OperationCancelledException());
} else {
result = new RemoteOperationResult(e);
}
}
// Added this line
result.setFileName(mLocalPath);
return result;
}
Related
I am trying to write a custom android print service. I have followed the instruction mentioned in the below blog:
https://github.com/zaki50/MyPrintServiceProject
I am able to create a service, which executes a print job. But after the job doesn't print any thing. My question is, what is the localId that we should provide. Is it printer ip, name? Also is there any way to know why the print job doesn't work.
Basically the two methods that I am concerned about are adding onStartPrinterDiscovery and OnPrintJobQueue as mentioned below:
#Override
public void onStartPrinterDiscovery(List<PrinterId> priorityList) {
String str = Settings.Secure.getString(getBaseContext().getContentResolver(), "enabled_print_services");
Log.d("myprinter", "PrinterDiscoverySession#onStartPrinterDiscovery(priorityList: " + priorityList + ") called")
final List<PrinterInfo> printers = new ArrayList<>();
final PrinterId printerId = generatePrinterId("D8:49:2F:64:04:DB");
final PrinterInfo.Builder builder = new PrinterInfo.Builder(printerId, "D8:49:2F:64:04:DB", PrinterInfo.STATUS_IDLE);
PrinterCapabilitiesInfo.Builder capBuilder = new PrinterCapabilitiesInfo.Builder(printerId);
capBuilder.addMediaSize(PrintAttributes.MediaSize.NA_LETTER, true);
capBuilder.addMediaSize(PrintAttributes.MediaSize.NA_LETTER, false);
capBuilder.addResolution(new PrintAttributes.Resolution("resolutionId", "default resolution", 600, 600), true);
capBuilder.setColorModes(PrintAttributes.COLOR_MODE_COLOR | PrintAttributes.COLOR_MODE_MONOCHROME, PrintAttributes.COLOR_MODE_COLOR);
builder.setCapabilities(capBuilder.build());
printers.add(builder.build());
addPrinters(printers);
}
#Override
protected void onPrintJobQueued(PrintJob printJob) {
Log.d("myprinter", "queued: " + printJob.getId().toString());
printJob.start();
//printJob.complete();
final PrintDocument document = printJob.getDocument();
final FileInputStream in = new FileInputStream(document.getData().getFileDescriptor());
try {
final byte[] buffer = new byte[4];
#SuppressWarnings("unused")
final int read = in.read(buffer);
Log.d("myprinter", "first " + buffer.length + "bytes of content: " + toString(buffer));
} catch (IOException e) {
Log.d("myprinter", "", e);
} finally {
try {
in.close();
} catch (IOException e) {
assert true;
}
}
if( printJob.isStarted()){
printJob.complete();
}
}
My Question is what should be printerId(or localId). How do we know if the printjob has succeeded or failed
You can do detection of print job status with other methods in the class:
if( printJob.isStarted() ){
}
else if( printJob.isCompleted() ){
}
else if( printJob.isCancelled() ){
}
else if( printJob.isFailed() ){
}
In addition, the print service has it's own methods listed in the docs:
#Override
protected void onPrintJobQueued(PrintJob printJob) {
Log.d("printer", "queued: " + printJob.getId().toString());
printJob.start();
//...
printJob.complete();
}
#Override
protected void onRequestCancelPrintJob(PrintJob printJob) {
Log.d("printer", "canceled: " + printJob.getId().toString());
printJob.cancel();
}
I am new to android, I have gone through many of the forums and discussions but still I am confused about what should I use for downloading large files from server!
In our App we are playing multiple videos in a playlist on the app frontend and meanwhile we are calling API service to get list videos in playlist, we are calling the API within an asynctask and onpostexecute method parse the API response and queue any new files to download in the downloadmanger.
The points of concern
Is using asynctask for fetching response from remote API enough? or is there any better option for us?
Calling download manager from main is a bad practice as I understand from reading, then whats the best way to go (Service, IntentService, Thread or AsyncTask)? What will be the difference of using Service, IntentService, Thread or AsyncTask in this scenario.
Can we execute the download when the app is kickedoff when in case of incoming call or user clicks home button, so the download should still continue and don't waste bandwidth, memory etc used for already downloaded part.
Can we initiate a download even if the app is in background?
Should we do the database operations in a different thread, is it the best practice?
public class MediaAsyncTask extends AsyncTask>
{
#Override
protected List<Media> doInBackground(String... params) {
List<Media> result = new ArrayList<Media>();
try {
ResponseHandler responseHandlerObj = new ResponseHandler(getApplicationContext());
result = responseHandlerObj.deviceMedia(device_id);
media_status = responseHandlerObj.getResponse_status();
media_msg = responseHandlerObj.getResponse_msg();
media_version = responseHandlerObj.getMedia_version();
medias_total = responseHandlerObj.getMedias_total();
} catch (Exception e) {
Log.d(TAG, e.getLocalizedMessage());
e.printStackTrace();
}
return result;
}
#Override
protected void onPostExecute(List<Media> result) {
Log.e(TAG, "status " + media_status);
if (media_status.equals(STATUS_SUCCESS)) {
Log.d(TAG, media_msg);
if (device_path != null) {
int _total_downloaded = databaseHandler.getDownloadedMediaCount(device_id);
int _total_in_api = medias_total;
int _downloaded_version = preferenceHelper.getDeviceMediaVersion(device_id);
Log.d(TAG, "media_version : " + media_version + " _downloaded_version : " + _downloaded_version + " _total_downloaded : " + _total_downloaded + " _total_in_api : " + _total_in_api);
//remove true after testing
if (media_version != _downloaded_version || _total_downloaded != _total_in_api) {
databaseHandler.deleteAllDeviceMedias(device_id);
int id;
String file;
for (Media media : result) {
id = 0;
file = media.getFile();
String file_url = media.getFile_url();
Log.d(TAG, "media file exists: " + fileManager.checkFileExists(device_path, file));
if (file != null && !fileManager.checkFileExists(device_path, file) && URLUtil.isValidUrl(file_url)) {
media.setDownloaded(0);
id = databaseHandler.saveMedia(media);
queueDownload(file_url, file);
} else if (fileManager.checkFileExists(device_path, file)) {
long app_size = (int) fileManager.getFileSize(device_path + "/" + file);
long server_size = media.getFile_size();
long server_size_minus = server_size - 100;
if (app_size < server_size_minus) {
fileManager.deleteFile(device_path + "/" + file);
queueDownload(file_url, file);
} else {
id = saveDownloadedResource(media);
}
}
}
}
if (download_files.size() == 0) {
Log.d(TAG, "nothing to download");
preferenceHelper.setDeviceMediaVersion(device_id, media_version);
}
}
} else {
Log.e(TAG, "Media: Failed to fetch data!");
}
}
private int saveDownloadedResource(Media media) {
int id = 0;
media.setDownloaded(1);
id = databaseHandler.saveMedia(media);
initUpdateLayoutOnNewResource();
return id;
}
}
I'm using Ion library for Android https://github.com/koush/ion
I download files from server and when I pass the url for file that is not on the server it is saved on sd card anyway. To be clear, let's assume I have following url: https://example.com/img/img_3.jpg but there is no such file. So actually this url is 404 Not Found, but ion creates a file img_3.jpg on my SD card. When I open the image it is blank. I've tried to check if downloaded file is empty, but it's not. So is there any possibility to forbid ion to download from not existing URL.
Here is my code:
private void executeDownload(final FilesToDownload downloadFiles) {
if (downloading != null && !downloading.isCancelled()) {
resetDownload();
return;
}
FileAndDirName fileAndDir = downloadFiles.popFileAndDirName();
final int size = downloadFiles.getFilesAndDirSize();
final String fileName = fileAndDir.getFileName();
final String dirName = fileAndDir.getDirName();
String url = mServerUrl + dirName + "/" + fileName;
File dir = new File(root.getAbsolutePath() + "/seatconnect/" + dirName);
if (!dir.exists()) {
dir.mkdirs();
}
final File destinationFile = new File(dir, fileName);
downloading = Ion.with(getActivity())
.load(url)
// attach the percentage report to a progress bar.
// can also attach to a ProgressDialog with progressDialog.
.progressBar(mProgressBar)
.progressDialog(mProgressDialog)
// callbacks on progress can happen on the UI thread
// via progressHandler. This is useful if you need to update a TextView.
// Updates to TextViews MUST happen on the UI thread.
.progressHandler(new ProgressCallback() {
#Override
public void onProgress(long downloaded, long total) {
// mProgressDialog.setProgress((int) downloaded);
}
})
// write to a file
.write(destinationFile)
// run a callback on completion
.setCallback(new FutureCallback<File>() {
#Override
public void onCompleted(Exception e, File result) {
resetDownload();
if (e != null) {
Toast.makeText(getActivity(), "Error downloading file " + fileName, Toast.LENGTH_SHORT).show();
// return;
} else {
Toast.makeText(getActivity(), "File download complete " + fileName, Toast.LENGTH_SHORT).show();
}
if (result.exists() && result.length() == 0) {
String message = result.delete() ? "Deleted empty file " : "The file is not empty ";
message += fileName;
Log.d(TAG, message);
}
if (size != 0) {
mProgressDialog.show();
executeDownload(downloadFiles);
return;
}
mProgressBar.setVisibility(View.INVISIBLE);
if (mProgressDialog.isShowing()) {
mProgressDialog.dismiss();
}
mNewsFooterCheckForUpdateButton.setVisibility(View.VISIBLE);
mNewsFooterUpdateButton.setVisibility(View.INVISIBLE);
}
});
}
Maybe too late but I think you can handle it by using withResponse()which basically embeds the downloaded file within a com.koushikdutta.ion.Response object, which of course contains headers. Then you can check them to be sure that no error code was returned.
downloading = Ion.with(getActivity())
.load(url)
.progressBar(mProgressBar)
.write(destinationFile)
.withResponse() // response will incapsulates the result file
.setCallback(new FutureCallback<Response<File>>()
#Override
public void onCompleted(Exception e, Response<File> response) {
File result = null;
if (e != null || response.getHeaders().code() != 200)) { // check response headers
// an error was occurred
// ...
} else {
// file was successfully downloaded
result = response.getResult();
// ...
}
});
I am developing an android application for mixing 2 audio files.And i use android ffmpeg for that.I use following lib. from GitHub
https://github.com/guardianproject/android-ffmpeg-java
I use following code to mix 2 audio files from activity .
try {
File fileAppRoot = new File(getApplicationInfo().dataDir);
SoxController sxCon = new SoxController(fileAppRoot, new ShellUtils.ShellCallback() {
#Override
public void shellOut(String shellLine) {
System.out.println(shellLine);
}
#Override
public void processComplete(int exitValue) {
System.out.println("hello");
}
});
List<String> files=new ArrayList<String>();
files.add(Environment.getExternalStorageDirectory().getAbsolutePath()+"/Testing/me.mp3");
files.add(Environment.getExternalStorageDirectory().getAbsolutePath()+"/Testing/il.mp3");
sxCon.combineMix(files,Environment.getExternalStorageDirectory().getAbsolutePath()+"/Testing/ial.mp3");
but this return exit value 2 on processComplete and no new file generated for mix audio.
This will return following problem in logs no handler for file extension `mp3'
Thanks for any help on this..
You cannot mix files mp3 with this library.
It cans mix files ".wave" only.
Let's convert your mp3 file to wave file then uset this lib to mix files wave.
I hope this response is good for you.
Thanks,
https://github.com/bravobit/FFmpeg-Android
implementation 'nl.bravobit:android-ffmpeg:1.1.7'
public boolean mergeAudio(final Context context, File[] voiceFile, String file_name) {
final ProgressDialog asyncDialog = new ProgressDialog(context);
asyncDialog.setMessage("Audio Merging Start..");
asyncDialog.setCancelable(false);
final boolean[] isSuccess = {false};
if (file_name != null) {
file_name = Environment.getExternalStorageDirectory() + "/podmod/" + file_name + "_.mp3";
} else {
file_name = getMusicFilename();
}
File ffmpegFile = new File(file_name);
if (ffmpegFile.exists()) {
ffmpegFile.delete();
}
for (File f : voiceFile) {
if (!f.exists()) {
Log.d("AudioMergingFailure", "File ot Exist");
return isSuccess[0];
}
}
String s = "";
String s_index = "";
String fileSize = "n=" + voiceFile.length;
for (int i = 0; i < voiceFile.length; i++) {
s = s + "-i#" + voiceFile[i].getPath() + "#";
s_index = s_index + "[" + i + ":0]";
}
String str_cmd = s + "-filter_complex#" + s_index + "concat=" + fileSize + ":v=0:a=1[out]#-map#[out]#" + file_name;
Log.d("str_cmd", str_cmd);
String[] cmd = str_cmd.split("#");
final String finalFile_name = file_name;
try {
if (FFmpeg.getInstance(context).isSupported()) {
FFmpeg ffmpeg = FFmpeg.getInstance(context);
// to execute "ffmpeg -version" command you just need to pass "-version"
ffmpeg.execute(cmd, new ExecuteBinaryResponseHandler() {
#Override
public void onStart() {
asyncDialog.show();
}
#Override
public void onProgress(String message) {
}
#Override
public void onFailure(String message) {
Log.d("AudioMergingFailure", message);
asyncDialog.dismiss();
Toast.makeText(context, "Audio Merging Failed",
Toast.LENGTH_LONG).show();
}
#Override
public void onSuccess(String message) {
asyncDialog.dismiss();
Log.v("onSuccess", message);
File ffmpegFile_ = new File(finalFile_name);
Toast.makeText(context, "Audio onSuccess",
Toast.LENGTH_LONG).show();
isSuccess[0] = true;
}
#Override
public void onFinish() {
asyncDialog.dismiss();
}
});
} else {
asyncDialog.dismiss();
}
} catch (Exception e) {
asyncDialog.dismiss();
Log.d("NotException_", e.getMessage());
}
return isSuccess[0];
}
public static String getMusicFilename() {
return Environment.getExternalStorageDirectory() + "/podmod/Merged_Audio_" + getRandomNumber(0, 100000) + ".mp3";
}
How to sync the entire image folder in Android phone to Dropbox using Dropbox Sync Api?
My app only has access to image file types as I want to only sync images to Dropbox. I got this error when I try to implement my current code:
03-04 20:38:42.010: W/libDropboxSync.so(thr)(23160): util.cpp:124: int dropbox_wait_for_first_sync(dbx_client_t*) should not be called on the main thread
03-04 20:38:42.020: W/libDropboxSync.so(ERR)(23160): DROPBOX_DISALLOWED: sync.hpp:300: app is not allowed to create file p(/i9)
Main part of the code:
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.dropbox_activity);
mTestOutput = (TextView) findViewById(R.id.test_output);
mLinkButton = (Button) findViewById(R.id.link_button);
mLinkButton.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
onClickLinkToDropbox();
}
});
mDbxAcctMgr = DbxAccountManager.getInstance(getApplicationContext(), appKey, appSecret);
}
#Override
protected void onResume() {
super.onResume();
if (mDbxAcctMgr.hasLinkedAccount()) {
showLinkedView();
doDropboxTest();
} else {
showUnlinkedView();
}
}
private void showLinkedView() {
mLinkButton.setVisibility(View.GONE);
mTestOutput.setVisibility(View.VISIBLE);
}
private void showUnlinkedView() {
mLinkButton.setVisibility(View.VISIBLE);
mTestOutput.setVisibility(View.GONE);
}
private void onClickLinkToDropbox() {
mDbxAcctMgr.startLink((Activity)this, REQUEST_LINK_TO_DBX);
}
#Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
if (requestCode == REQUEST_LINK_TO_DBX) {
if (resultCode == Activity.RESULT_OK) {
doDropboxTest();
} else {
mTestOutput.setText("Link to Dropbox failed or was cancelled.");
}
} else {
super.onActivityResult(requestCode, resultCode, data);
}
}
private void doDropboxTest() {
mTestOutput.setText("Dropbox Sync API Version "+DbxAccountManager.SDK_VERSION_NAME+"\n");
try {
final String TEST_DATA = "Hello Dropbox";
final String TEST_FILE_NAME = "Pars";
DbxPath testPath = new DbxPath(DbxPath.ROOT, TEST_FILE_NAME);
// Create DbxFileSystem for synchronized file access.
DbxFileSystem dbxFs = DbxFileSystem.forAccount(mDbxAcctMgr.getLinkedAccount());
// Print the contents of the root folder. This will block until we can
// sync metadata the first time.
List<DbxFileInfo> infos = dbxFs.listFolder(DbxPath.ROOT);
mTestOutput.append("\nContents of app folder:\n");
for (DbxFileInfo info : infos) {
mTestOutput.append(" " + info.path + ", " + info.modifiedTime + '\n');
}
// Create a test file only if it doesn't already exist.
if (!dbxFs.exists(testPath)) {
DbxFile testFile = dbxFs.create(testPath);
try {
testFile.writeString(TEST_DATA);
} finally {
testFile.close();
}
mTestOutput.append("\nCreated new file '" + testPath + "'.\n");
}
// Read and print the contents of test file. Since we're not making
// any attempt to wait for the latest version, this may print an
// older cached version. Use getSyncStatus() and/or a listener to
// check for a new version.
if (dbxFs.isFile(testPath)) {
String resultData;
DbxFile testFile = dbxFs.open(testPath);
try {
resultData = testFile.readString();
} finally {
testFile.close();
}
mTestOutput.append("\nRead file '" + testPath + "' and got data:\n " + resultData);
} else if (dbxFs.isFolder(testPath)) {
mTestOutput.append("'" + testPath.toString() + "' is a folder.\n");
}
} catch (IOException e) {
mTestOutput.setText("Dropbox test failed: " + e);
}
}
Your code tries to write a file called Pars, but you only have permission to write image files (ones with extensions like .jpg, .png, etc.). If you change your filename to something with an image extension, like Pars.jpg, you'll be able to write it.