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();
}
}
}
Related
I know that is easy to take a photo and save it to Gallery.
protected async Task<MediaFile> TakePhoto()
{
var storageOptions = new StoreCameraMediaOptions()
{
SaveToAlbum = true,
Directory = pictureAlbumName,
Name = $"test_{DateTime.Now.ToString("HH_mm_ss_ff")}.jpg"
};
return await CrossMedia.Current.TakePhotoAsync(storageOptions);
}
As the result I got the URL that looks like this:
/storage/emulated/0/Android/data/com.companyname.appname/files/Pictures/MyAlbum/photo_18_47_29_69.jpg
But when I tried to save the image from bytes it appears in the folder but never appears in the gallery. After saving the image I tried of course to scan the newly created path but there was no effect
First attempt
File.WriteAllBytes("/storage/emulated/0/Android/data/com.companyname.appname/files/Pictures/MyAlbum/downloaded_image_223213a3as.jpg", immageBytes);
MediaScannerConnection.ScanFile(Application.Context, new string[] { path },null,null);
Second attempt using obsoleted Android methods
Java.IO.File storagePath = Android.OS.Environment.GetExternalStoragePublicDirectory(Android.OS.Environment.DirectoryPictures);
string path = System.IO.Path.Combine(storagePath.ToString(), filename);
System.IO.File.WriteAllBytes(path, imageByte);
var mediaScanIntent = new Intent(Intent.ActionMediaScannerScanFile);
mediaScanIntent.SetData(Android.Net.Uri.FromFile(new Java.IO.File(path)));
CurrentContext.SendBroadcast(mediaScanIntent);
Update:
Basically you need to use this method and save it
private void SaveImageToStorage(Bitmap bitmap)
{
Stream imageOutStream;
if (Build.VERSION.SdkInt >= BuildVersionCodes.Q)
{
ContentValues values = new ContentValues();
values.Put(MediaStore.IMediaColumns.DisplayName,
"image_screenshot.jpg");
values.Put(MediaStore.IMediaColumns.MimeType, "image/jpeg");
values.Put(MediaStore.IMediaColumns.RelativePath,
Android.OS.Environment.DirectoryPictures + Java.IO.File.PathSeparator + "AppName");
Android.Net.Uri uri = this.ContentResolver.Insert(MediaStore.Images.Media.ExternalContentUri, values);
imageOutStream = ContentResolver.OpenOutputStream(uri);
}
else
{
String imagesDir =Android.OS.Environment.GetExternalStoragePublicDirectory(Android.OS.Environment.DirectoryPictures).ToString() + "/AppName";
imageOutStream = File.OpenRead(System.IO.Path.Combine(imagesDir, "image_screenshot.jpg"));
}
bitmap.Compress(Bitmap.CompressFormat.Jpeg, 100, imageOutStream);
imageOutStream.Close();
}
OG Answer:
As far as I know, Only images in your media store provider are visible to your gallery and to add it to the media store you need to use the following:
MediaStore.Images.Media.InsertImage(Activity.ContentResolver, ImgBitmap, yourTitle , yourDescription);
Hope this helps :)
I'm trying to share photos to instagram and I have this error 'file format not supported' or 'image format not supported'.
Please, Can anyone help me?
I'm working with Xamarin forms, using a function of the Android Project thanks to DependencyService from the general project.
public bool LaunchApp(string path)
{
bool result = false;
String type = "image/*";
String mediaPath = path;
try
{
// Create the new Intent using the 'Send' action.
Intent share = new Intent(Intent.ActionSend);
var aUri = Uri.Parse(mediaPath);
File media = new File(mediaPath);
// Add the URI to the Intent.
share.PutExtra(Intent.ExtraStream, Uri.FromFile(media));
// Set the MIME type
share.SetType(type);
//var intent = new Intent(Intent.ActionView, aUri);
Xamarin.Forms.Forms.Context.StartActivity(Intent.CreateChooser(share, "Share to"));
result = true;
}
catch (ActivityNotFoundException)
{
result = false;
}
return result;
}
}
path = "/storage/emulated/0/Android/data/com.BlogsterApp_Ambassador.app/files/Pictures/temp/Screenshot_20190728_222104.jpg" (this path is built with GetGalleryPhotoAsync())
{
I also trying:
-var aUri = Android.Net.Uri.Parse(new Uri(mediaPath).ToString());
- share.PutExtra(Intent.ExtraStream, aUri);
shareIntent.AddFlags(Android.Content.ActivityFlags.GrantReadUriPermission);
or
Android.Net.Uri uri = Android.Net.Uri.Parse($"file//:{path}");
Could help prevent these errors.
I am developing an Android app from which I want to launch MS office apps to view and edit office files. For example, open a docx stored locally in the device for editing in MS-Word mobile app.
Previously we were opening such file with a file URI passed in an intent with e.g. the "com.microsoft.office.word" package name. The file would open in Word for Android and the user could edit it and save it. No problem.
Now we had to change so that we use the FileProvider class of Android with the permissions for reading and writing. With this implementation other apps can edit the files but Microsoft Office apps for Android are opened in read-only mode with no option to change it.
This seem to be a common issue that happens to others too, as seen in other stackoverflow questions:
When using Android file provider, files don't have correct permissions despite FLAG_GRANT_WRITE_URI_PERMISSION being flagged in intent
and
Xamarin.Forms Android FileProvider: GrantWriteUriPermission not always working
I have also found this link with information about how to invoke the office apps in msdn, but it seems quite incomplete and I haven't been able to make it work with an intent and a local file (I just don't know how to send the ms-word:ofe|u|file so that it recognizes it, it always complains it cannot find the file).
Does anyone know a way to open a local file in edit mode from an android app in microsoft office for Android using FileProvider?
I haven't posted any code as it is no issue with it. Any other app works fine, but Microsoft Office apps.
I wrote a common open routine and then broke out individual file types like below. I haven't had issues after doing the following. Hopefully this helps. (note - I only added the word call - but use the types from the SO article here(What is a correct mime type for docx, pptx etc?)
public static Java.IO.File CopyDocuments(Java.IO.File source, string realName)
{
//string path = System.Environment.GetFolderPath(System.Environment.SpecialFolder.MyDocuments); <-- old method
string path = Android.OS.Environment.GetExternalStoragePublicDirectory(Android.OS.Environment.DirectoryDownloads).AbsolutePath;
if (!System.IO.Directory.Exists(Path.Combine(path, "appname")))
System.IO.Directory.CreateDirectory(Path.Combine(path, "appname"));
string dbPath = Path.Combine(path,"appname", realName);
Java.IO.File destination = new Java.IO.File(dbPath);
try
{
//if (destination.Exists())
// destination.Delete();
if (!destination.Exists())
{
using (FileStream fs = new FileStream(source.AbsolutePath, FileMode.Open, FileAccess.Read))
{
using (var br = new BinaryReader(fs))
{
using (var bw = new BinaryWriter(new FileStream(dbPath, FileMode.Create)))
{
byte[] buffer = new byte[2048];
int length = 0;
while ((length = br.Read(buffer, 0, buffer.Length)) > 0)
{
bw.Write(buffer, 0, length);
}
}
}
}
}
return destination;
}
catch (Exception ex)
{
Toast.MakeText(Xamarin.Forms.Forms.Context, "Error Copying: " + ex.Message, ToastLength.Long).Show();
}
return null;
}
public void LaunchApp(string fileLocation, string realName)
{
var file = new Java.IO.File(fileLocation);
if (!file.Exists())
return;
file = CopyDocuments(file, realName);
Intent intent = null;
var extension = System.IO.Path.GetExtension(fileLocation).ToLower();
switch (extension)
{
case ContentService.DocxExtension:
intent = ReturnWord(file, true);
break;
case ContentService.DocExtension:
intent = ReturnWord(file, false);
break;
case ContentService.TxtExtension:
case PlayerLync.Services.ContentService.RtfExtension:
intent = ReturnText(file);
break;
case ContentService.XlsExtension:
intent = ReturnExcel(file, false);
break;
case ContentService.XlsxExtension:
intent = ReturnExcel(file, true);
break;
case ContentService.PPExtension:
intent = ReturnPowerPoint(file, false);
break;
case ContentService.PPXExtension:
intent = ReturnPowerPoint(file, true);
break;
case ContentService.Mp3Extension:
//contentType = ContentType.Audio;
break;
default:
//contentType = ContentType.Unknown;
break;
}
try
{
Xamarin.Forms.Forms.Context.StartActivity(intent);
}
catch (Exception ex)
{
... log error
}
}
private Intent ReturnWord(Java.IO.File file, bool isEx)
{
var intent = new Intent(Intent.ActionView);
Android.Net.Uri uri = FileProvider.GetUriForFile(Xamarin.Forms.Forms.Context, "your_package.fileprovider", file);// --> old method Android.Net.Uri.FromFile(file); //
intent.AddFlags(ActivityFlags.GrantReadUriPermission);
intent.AddFlags(ActivityFlags.GrantWriteUriPermission);
intent.AddFlags(ActivityFlags.GrantPersistableUriPermission);
intent.PutExtra(Intent.ExtraStream, uri);
if (!isEx)
{
intent.SetDataAndType(uri, "application/vnd.msword");
}
else
{
intent.SetDataAndType(uri, "application/vnd.openxmlformats-officedocument.wordprocessingml.document");
}
return intent;
}
Place this all in Android project and do a custom renderer to access it from Xamarin Forms
Intent tostart = new Intent(Intent.ACTION_VIEW);
tostart.setDataAndType(Uri.parse(video_path+".***"), "video/*");
startActivity(tostart);
Let's say I have a file path
/mnt/sdcard/video/my_birthday_moovie001
'my_birthday_moovie001' can be either .mkv, .mpg or .mkv. I've tried to add ".***" to the file path but I still can't open the file.
Well i read the comments you have stored your path in db without extensions there are many extensions that exists so android cant automatically pick the extension you have to create some way to detect extension.
following is a robust way that is best match in your case but not recommended in proper cases where extensions are known
public String chk_path(String filePath)
{
//create array of extensions
String[] ext=new String[]{".mkv",".mpg"}; //You can add more as you require
//Iterate through array and check your path which extension with your path exists
String path=null;
for(int i=0;i<ext.Length;i++)
{
File file = new File(filePath+ext[i]);
if(file.exists())
{
//if it exists then combine the extension
path=filePath+ext[i];
break;
}
}
return path;
}
now to play a song in your code
if(chk_path(video_path)!=null)
{
Intent tostart = new Intent(Intent.ACTION_VIEW);
tostart.setDataAndType(Uri.parse(video_path), "video/*");
startActivity(tostart);
}
else
//tell user that although the path in database but file on this path do not exists
Well as I put on comments
You could compare if the path matches with any filename(it doesn't contains the extension) and then if it does you got it.
You can simply do this :
Get the directory path
File extStore = Environment.getExternalStorageDirectory();
Set the file name my_birthday_moovie001 on my example I put unnamed but change it as your like
String NameOfFile = "unnamed";
Add the videos, I put it Downloads but you can change it
String PathWithFolder = extStore + "/Download/";
Create a method that lists all the files from your path
private List<String> getListFiles(File parentDir) {
ArrayList<String> inFiles = new ArrayList<String>();
File[] files = parentDir.listFiles();
for (File file : files) {
if (file.isDirectory()) {
inFiles.addAll(getListFiles(file));
} else {
String AbsolutePath = file.getAbsolutePath();
//Get the file name ex : unnamed.jpg
String nameofFile = AbsolutePath.substring(AbsolutePath.lastIndexOf("/") + 1, AbsolutePath.length());
//Remove the .jpg --> Output unnamed
String fileNameWithoutExtension = nameofFile.substring(0, nameofFile.lastIndexOf('.'));
//Add each file
inFiles.add(fileNameWithoutExtension);
}
}
return inFiles;
}
You got the names of the files doing this
List<String> files = getListFiles(new File(PathWithFolder));
Simply add a for that looks for a match of your file
for (int i = 0; i<=files.size()-1; i++){
if(PathWithFolder.equals(files.get(i))) {
Toast.makeText(MainActivity.this, "You got it!", Toast.LENGTH_SHORT).show();
}
else{
Toast.makeText(MainActivity.this, "You don't.", Toast.LENGTH_SHORT).show();
}
}
If you want to get the path as well and do what #Zain Ul Abidin proposed and compare it on getListFiles() method add this :
String fileExtension = nameofFile.substring(nameofFile.lastIndexOf("."));
Hope it helps.
From the other question :
Consider DirectoryScanner from Apache Ant:
DirectoryScanner scanner = new DirectoryScanner();
scanner.setIncludes(new String[]{"**/*.java"});
scanner.setBasedir("C:/Temp");
scanner.setCaseSensitive(false);
scanner.scan();
String[] files = scanner.getIncludedFiles();
You'll need to reference ant.jar (~ 1.3 MB for ant 1.7.1).
And then, run on files array and check
if files[i].include(yourfile)
yourfile= files[i]
You may try in this way , first getting the name of file and extension then finally compare and implement. like this :
Example file name is 04chamelon and extension is .png:
File f = new File("/mnt/storage/sdcard/Pictures/04chameleon");
File yourDir = new File("/mnt/storage/sdcard/Pictures");
nametwo = f.getName();
for (File fa : yourDir.listFiles()) {
if (fa.isFile())
fa.getName();
String path = fa.getName(); // getting name and extension
filextension = path.substring(path.lastIndexOf(".") + 1); // seperating extension
name1 = fa.getName();
int pos = name1.lastIndexOf(".");
if (pos > 0) {
name1 = name1.substring(0, pos);
}
}
if (name1.equals(nametwo)) {
Intent tostart = new Intent(Intent.ACTION_VIEW);
tostart.setDataAndType(Uri.parse(f + "." + filextension), "image/*");
//tostart.setDataAndType(Uri.parse(f + "." + filextension), "video/*");
startActivity(tostart);
}
With the latest ContentResolver, you can easily make this work using the contentResolver.getType(uri) function which detects the filetype.
private fun getIntentForFile(intent: Intent, filePath: String, context: Context): Intent {
val uri = FileProvider.getUriForFile(
context,
context.applicationContext.packageName + ".fileprovider",
File(filePath)
)
intent.putExtra(Intent.EXTRA_STREAM, uri)
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
intent.setDataAndType(uri, context.contentResolver.getType(uri))
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
return intent
}
I've coded my own file explorer and now I want to start to Implement capabilities to open various files. I have implemented Mime Types and all other things but how can I parse specific selected file to specific "viewer activity"? I know by using intents but how to receive it in that viewer app and use it. Many thanks guys :)
Something like this should work. Change file to whatever you want.
File file = new File(Environment.getExternalStorageDirectory(), "movie.mp4");
int index = file.getName().lastIndexOf(".") + 1;
String extension = null;
if (index > 0) {
extension = file.getName().substring(index);
}
Intent intent = new Intent(android.content.Intent.ACTION_VIEW);
Uri u = Uri.parse("file://" + file.getAbsolutePath());
String mimeType = null;
if (extension != null) {
mimeType = MimeTypeMap.getSingleton().getMimeTypeFromExtension(extension);
}
if (mimeType == null) {
mimeType = "*/*";
}
intent.setDataAndType(u, mimeType);
try {
startActivity(Intent.createChooser(intent, "Open with..."));
} catch (ActivityNotFoundException e) {
// handle the exception
}