I need to upload files using multipart form.
I can upload images from path below:
/storage/emulated/0/Pictures/Screenshots/Screenshot_20160614-224624.png
However, when I try to upload a PDF file, it fails. PDF file path is :
/storage/emulated/0/Android/data/com.google.android.apps.docs/cache/projector/pdf.pdf
Can any one tell me why it is work with image and fail with pdf ??
This is my code :
try {
MultipartUtility multipart = new MultipartUtility(ForSaleConstants.EXTRA_FILE_UPLOADER, ForSaleNetworkManager.CHARACTER_SET);
multipart.addFormField(ForSaleConstants.DEVICE_ID, deviceId);
String uriString = extraFileUri.toString();
Log.e("File_URI", uriString);
uriString = Uri.decode(uriString);
if (uriString.contains("file://")) {
uriString = uriString.replace("file://", "");
File uploadFile = new File(uriString);
multipart.addFilePart(("file"), uploadFile);
} else if (uriString.contains("content://")) {
uriString = FileManager.getInstance().getRealPathFromImageUri(context, Uri.parse(uriString));
File uploadFile = new File(uriString);
multipart.addFilePart(("file"), uploadFile);
} else {
try {
File uploadFile = new File(uriString);
multipart.addFilePart(("file"), uploadFile);
}catch (Exception e) {
}
}
List<String> response = multipart.finish();
if(response != null && response.size() > 0) {
mStopTime = System.nanoTime();
PerformanceManager.getInstance().showCalculatedTime("uploadExtraFile [doInBackground]", mStartTime, mStopTime);
JSONObject json = ForSaleNetworkManager.convertStringToJSONObject(response.get(0));
BaseResponse response1 = new BaseResponse(json, null);
return response1;
}
} catch (Exception e) {
e.printStackTrace();
uiListener.onUploadExtraFileCompleted(null, AppError.DATA_ERROR);
return null;
}
Is this your application package ?
com.google.android.apps.docs
/storage/emulated/0/Android/data/com.google.android.apps.docs/cache/projector/pdf.pdf
If not you cannot access it because of sandboxing.
Update
Each android application run in its own linux process hence you cannot access files in different application unless its stored in the common location. Like your image is. Hence you are not able to upload the pdf file
Related
i'm getting a pdf file from an api, and i got something like that http://x/docs/document1
In my android project, i have like this:
try{
Android.Content.Intent activity = new Android.Content.Intent(this, typeof(WebViewPDF));
activity.AddFlags(Android.Content.ActivityFlags.GrantReadUriPermission);
activity.AddFlags(Android.Content.ActivityFlags.NoHistory);
string uriAndroid = "http://x/docs/document1";
activity.PutExtra("url", JsonConvert.SerializeObject(uriAndroid));
StartActivity(activity);
}catch (Exception){
...
}
The main problem is, i cannot modify the api, so the endpoint is http://x/docs/document1, but if i try another uri, with the .pdf extension, for example https://www.w3.org/WAI/ER/tests/xhtml/testfiles/resources/pdf/dummy.pdf it works fine.
I don't know if i need to get that info from the API in a different way,
How can i show the pdf in the webView or external app without download first the doc?
The solution was download first and then open from local.
void PrintPdf(Uri uri)
{
var webClient = new WebClient();
webClient.Proxy = WebRequest.DefaultWebProxy;
webClient.Credentials = new NetworkCredential("UserName", "Pass");
webClient.Encoding = Encoding.UTF8;
var bytes = webClient.DownloadData(uri);
var text = bytes; // get the downloaded text
string localFilename = "NameforPdf.PDF";
string localPath = System.IO.Path.Combine(Android.OS.Environment.GetExternalStoragePublicDirectory(Android.OS.Environment.DirectoryDownloads).ToString(), localFilename);
File.WriteAllBytes(localPath, text); // writes to local storage
bool exists = File.Exists(localPath);
if (exists)
{
Java.IO.File file = new Java.IO.File(localPath);
file.SetReadable(true);
//That's the important part, notice the content://
Android.Net.Uri uriLocal = Android.Net.Uri.Parse("content://" + localPath);
Intent intent = new Intent(Intent.ActionView);
intent.SetFlags(ActivityFlags.NewTask);
intent.SetDataAndType(uriLocal, "application/pdf");
intent.AddFlags(ActivityFlags.GrantReadUriPermission);
try
{
StartActivity(intent);
}
catch (Exception)
{
Toast.MakeText(Xamarin.Forms.Forms.Context, "pdf reader not installed", ToastLength.Short).Show();
}
}
}
I am trying to download an image using a url through a service I've created and when I inspect my device's file directory through Android Studio debugger, I can see the file in the device:
The red file is the downloaded file in question. The green image file is a file I manually dragged in to the directory through Windows Explorer.
I can successfully see and open the green file in my Gallery app but the red file (and all the other files listed in that directory) are no where to be found. I cannot see them in Windows Explorer either. Am I supposed to identify them as images somewhere in my code so that the file system knows it's an image?
This is the part where I download the image:
Request.Builder builder = new Request.Builder();
builder = builder.url(downloadFileUrl);
builder = builder.addHeader("RANGE", "bytes=" + existLocalFileLength);
Request request = builder.build();
Call call = okHttpClient.newCall(request);
Response response = call.execute();
if (response != null && response.isSuccessful()) {
RandomAccessFile downloadFile = new RandomAccessFile(existLocalFile, "rw");
downloadFile.seek(existLocalFileLength);
ResponseBody responseBody = response.body();
InputStream inputStream = responseBody.byteStream();
BufferedInputStream bufferedInputStream = new BufferedInputStream(inputStream);
byte data[] = new byte[102400];
long totalReadLength = 0;
int readLength = bufferedInputStream.read(data);
while (readLength != -1) {
if (getDownloadManager().isDownloadPaused()) {
ret = DOWNLOAD_PAUSED;
break;
} else if (getDownloadManager().isDownloadCanceled()) {
ret = DOWNLOAD_CANCELED;
break;
} else {
downloadFile.write(data, 0, readLength);
totalReadLength = totalReadLength + readLength;
int downloadProgress = (int)((totalReadLength + existLocalFileLength) * 100 / downloadFileLength);
getDownloadManager().updateTaskProgress(downloadProgress);
readLength = bufferedInputStream.read(data);
}
}
}
You need to scan the saved file using MediaScannerConnection:
private void scanFile(String path) {
MediaScannerConnection.scanFile(context,
new String[] { path }, null,
new MediaScannerConnection.OnScanCompletedListener() {
public void onScanCompleted(String path, Uri uri) {
Log.d("Tag", "Scan finished. You can view the image in the gallery now.");
}
});
}
Call this on your existLocalFile's path:
scanFile(existLocalFile.getAbsolutePath());
I am used to opening my files in my apps using the next code:
public void openFile(#NonNull String uri) {
checkNotNull(uri);
File file = new File(uri);
String dataType = null;
if (ContentTypeUtils.isPdf(uri)) dataType = "application/pdf";
else if (ContentTypeUtils.isImage(uri)) dataType = "image/*";
if (file.exists() && dataType != null) {
Intent target = new Intent(Intent.ACTION_VIEW);
target.setDataAndType(Uri.fromFile(file), dataType);
target.setFlags(Intent.FLAG_ACTIVITY_NO_HISTORY);
Intent intent = Intent.createChooser(target, "Open file");
try {
startActivity(intent);
} catch (ActivityNotFoundException e) {
e.printStackTrace();
Log.e(TAG, "There is a problem when opening the file :(");
}
} else {
Toast.makeText(getContext(), "Invalido", Toast.LENGTH_LONG).show();
}
}
I had always used static files so this was enough, but now I am using the Google Drive SDK for Android. I possess the driveId of the file I want to open but the problem is I cannot find a clean way to open the file contents I obtain by doing this:
Drive.DriveApi.fetchDriveId(mGoogleApiClient, documentFile.getDriveId())
.setResultCallback(driveIdResult -> {
PendingResult<DriveApi.DriveContentsResult> open =
driveIdResult.getDriveId().asDriveFile().open(
mGoogleApiClient,
DriveFile.MODE_READ_ONLY,
null);
open.setResultCallback(result -> {
DriveContents contents = result.getDriveContents();
InputStream inputStream = contents.getInputStream();
// I know I can get the input stream, and use it to write a new file.
});
});
So the only thing that comes to my mind is creating a static route to create a file every time I have to open it, and erasing it every time I have to open a new file.
What I have understood up until now is that the Google Drive API for Android already saves an instance of the file so what I have in mind sounds unnecessary, I would like to know if there is a better way to achieve this. Is there a way I can open the file and do something similar to what I do with the Intent.ACTION_VIEW in a cleaner way?
Thanks in advance.
Well since it seems this will not be answered I will post what I did. All I did was create a temp file where I put my contents to be read. I still don't know if it was the best choice so this question will still be opened for a better answer.
open.setResultCallback(result -> {
DriveContents contents = result.getDriveContents();
InputStream inputStream = contents.getInputStream();
writeTempFile(inputStream);
});
And here the implementation of the `writeTempFile`:
private synchronized File writeTempFile(#NonNull InputStream inputStream) {
checkNotNull(inputStream);
File filePath = new File(mActivity.getFilesDir(), "TempFiles");
if (!filePath.exists()) filePath.mkdirs();
File file = new File(filePath, TEMP_FILE);
try {
OutputStream outputStream = new FileOutputStream(file);
IOUtils.copyLarge(inputStream, outputStream);
IOUtils.closeQuietly(inputStream);
IOUtils.closeQuietly(outputStream);
} catch (IOException e) {
e.printStackTrace();
}
return file;
}
I'm able to upload database to Drive using the following post.
Drive API - Download/upload sql database
But I'm not able to access it directly offline without using app.
Aim: Use the db file further in different application so I want it to be in a usable format whenever I download the content directly from google drive.
I am using MODE_WRITE_ONLY to upload the file to drive from within app
mfile.open(api, DriveFile.MODE_WRITE_ONLY, new DriveFile.DownloadProgressListener()
And mime type as this String mimeType = MimeTypeMap.getSingleton().getExtensionFromMimeType("db");
My db size is 44kb when I access from external sd card on phone, however it shows 40kb when I see on drive. Please suggest what can I do to make it readable so that I can directly open it in an sqlite browser because when I open it shows "File not recognized".
Do I have to make changes in the WRITE only part or mime type for db file. Please suggest what could be the problem.
Since I've successfully tested an SQLite file upload to GooDrive, I can post a piece of code that does it:
Let's assume, there is a SQLite file on your android device:
java.io.File dbFile = Context.getDatabasePath([YOUR_DB_NAME])
Then you can call this method:
upload("temp.db", dbFile, "application/x-sqlite3")
com.google.android.gms.common.api.GoogleApiClient GAC;
///...
void upload(final String titl, final File file, final String mime) {
if (GAC != null && GAC.isConnected() && titl != null && file != null) try {
Drive.DriveApi.newDriveContents(GAC).setResultCallback(new ResultCallback<DriveContentsResult>() {
#Override
public void onResult(#NonNull DriveContentsResult contRslt) {
if (contRslt.getStatus().isSuccess()){
DriveContents cont = contRslt.getDriveContents();
if (cont != null && file2Os(cont.getOutputStream(), file)) {
MetadataChangeSet meta = new Builder().setTitle(titl).setMimeType(mime).build();
Drive.DriveApi.getRootFolder(GAC).createFile(GAC, meta, cont).setResultCallback(
new ResultCallback<DriveFileResult>() {
#Override
public void onResult(#NonNull DriveFileResult fileRslt) {
if (fileRslt.getStatus().isSuccess()) {
// fileRslt.getDriveFile(); BINGO !!!
}
}
}
);
}
}
}
});
} catch (Exception e) { e.printStackTrace(); }
}
static boolean file2Os(OutputStream os, File file) {
boolean bOK = false;
InputStream is = null;
if (file != null && os != null) try {
byte[] buf = new byte[4096];
is = new FileInputStream(file);
int c;
while ((c = is.read(buf, 0, buf.length)) > 0)
os.write(buf, 0, c);
bOK = true;
} catch (Exception e) {e.printStackTrace();}
finally {
try {
os.flush(); os.close();
if (is != null )is.close();
} catch (Exception e) {e.printStackTrace();}
}
return bOK;
}
To create a "temp.db" SQLite file in the root of your GooDrive.
You can certainly supply a different parent folder (instead of Drive.DriveApi.getRootFolder(GAC)) if you need to place your file in a different location.
I am Working email attachment .I am facing one problem while attachment .Problem Is that i want to sent a mail with attachment .I have one file on this path sdcard0 then fgg then hh.html.When I debug
on this File file = new File(attachments.getString(i));
it show file:/storage/sdcard0/fgg/hh.html
But After this it not go to if condition why ?
File file = new File(attachments.getString(i));
if (file.exists()) {
Uri uri = Uri.fromFile(file);
uris.add(uri);
}
Here is my hole code
JSONArray attachments = parameters.getJSONArray("attachments");
if (attachments != null && attachments.length() > 0) {
ArrayList<Uri> uris = new ArrayList<Uri>();
//convert from paths to Android friendly Parcelable Uri's
for (int i=0; i<attachments.length(); i++) {
try {
File file = new File(attachments.getString(i));
if (file.exists()) {
Uri uri = Uri.fromFile(file);
uris.add(uri);
}
} catch (Exception e) {
LOG.e("EmailComposer", "Error adding an attachment: " + e.toString());
}
}
if (uris.size() > 0) {
emailIntent.putParcelableArrayListExtra(Intent.EXTRA_STREAM, uris);
}
}
} catch (Exception e) {
LOG.e("EmailComposer", "Error handling attachments param: " + e.toString());
}
Uri to file will need triple slashes :
file:///storage/sdcard0/fgg/hh.html
As you can see here.
But i twill probably not work, so try to remove the "file:" part of your string :
File file = new File(attachments.getString(i).replace("file:","");
in a URI, you have different parts.
First the scheme:
http://
file://
ftp://
Then the path you want to access:
myfile.txt
videos/myvideo.avi
/storage/sdcard0/fgg/hh.html
So your complete URI should be:
file:///storage/sdcard0/fgg/hh.html
More information here:
http://developer.android.com/reference/java/net/URI.html
You can then build your File and check if it exist with this snippet
Uri.Builder builder = new Uri.Builder();
builder.scheme("file");
builder.path(myFilePath);
Uri uri = builder.build();
File file = new File(uri.getPath());
if (file.exists()) {
uris.add(uri);
// do whatever you want
}
EDIT:
If your JSON send you complete URI path, use this code instead:
Uri uri = Uri.parse(attachments.getString(i));
File file = new File(uri.getPath());
if (file.exists()) {
uris.add(uri);
// do whatever you want
}
Try two forward slashes after :
file://storage/sdcard0/fgg/hh.html
edit:
should be 3 forward slashes