Error opening camera with Xamarin.Forms and Prism - xamarin

Code Behind
async Task BtnCameraEvento()
{
try
{
await CrossMedia.Current.Initialize();
//Verifica se a camera está disponivel
if (!CrossMedia.Current.IsTakePhotoSupported || !CrossMedia.Current.IsCameraAvailable)
{
await App.Current.MainPage.DisplayAlert("Aviso", "Nenhuma camera detectada", "OK");
return;
}
//tira a foto
var file = await CrossMedia.Current.TakePhotoAsync(
new StoreCameraMediaOptions
{
SaveToAlbum = false,
Directory = "Demo",
Name = "foto"
});
//Verifica se foi tirado alguma foto
if (file == null)
return;
//Adiciona a foto a lista de imagens
_imageList.Add(file.Path);
}
catch (Exception ex)
{
int x = 1;
}
}
The following error appears in the line "CrossMedia.Current.TakePhotoAsync":
"Unable to get file location. This most likely means that the file provider information is not set in your Android Manifest file. Please check documentation on how to set this up in your project."

See particularly this section of the docs linked by sushihangover:
https://github.com/jamesmontemagno/MediaPlugin#android
Copied here in case link ever breaks:
Android
The WRITE_EXTERNAL_STORAGE & READ_EXTERNAL_STORAGE permissions are required, but the library will automatically add this for you. Additionally, if your users are running Marshmallow the Plugin will automatically prompt them for runtime permissions. You must add the Permission Plugin code into your Main or Base Activities:
Add to Activity:
public override void OnRequestPermissionsResult(int requestCode, string[]
permissions, Android.Content.PM.Permission[] grantResults)
{
Plugin.Permissions.PermissionsImplementation.
Current.OnRequestPermissionsResult
(requestCode, permissions, grantResults);
}
Android Current Activity Setup
This plugin uses the Current Activity Plugin to get access to the current Android Activity. Be sure to complete the full setup if a MainApplication.cs file was not automatically added to your application. Please fully read through the Current Activity Plugin Documentation. At an absolute minimum you must set the following in your Activity's OnCreate method:
CrossCurrentActivity.Current.Init(this, bundle);
It is highly recommended that you use a custom Application that are outlined in the Current Activity Plugin Documentation](https://github.com/jamesmontemagno/CurrentActivityPlugin/blob/master/README.md)
Android Misc Setup
By adding these permissions Google Play will automatically filter out devices without specific hardware. You can get around this by adding the following to your AssemblyInfo.cs file in your Android project:
[assembly: UsesFeature("android.hardware.camera", Required = false)]
[assembly: UsesFeature("android.hardware.camera.autofocus", Required = false)]
Android File Provider Setup
You must also add a few additional configuration files to adhere to the new strict mode:
1.) Add the following to your AndroidManifest.xml inside the <application> tags:
<provider android:name="android.support.v4.content.FileProvider"
android:authorities="${applicationId}.fileprovider"
android:exported="false"
android:grantUriPermissions="true">
<meta-data android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="#xml/file_paths"></meta-data>
</provider>
2.) Add a new folder called xml into your Resources folder and add a new XML file called file_paths.xml. Make sure that this XML file has a Build Action of: AndroidResource.
Add the following code:
<?xml version="1.0" encoding="utf-8"?>
<paths xmlns:android="http://schemas.android.com/apk/res/android">
<external-files-path name="my_images" path="Pictures" />
<external-files-path name="my_movies" path="Movies" />
</paths>
You can read more at: https://developer.android.com/training/camera/photobasics.html

Related

Download path in Xamarin iOS

I am using Xamarin.Forms and written the code to download the file for the iOS
platform. It is downloading the file successfully without any error. But after downloading it, I am not able to find the downloaded file in my apple device.
During debugging I found that it is showing
/var/mobile/Containers/Data/Application/1234567A-B8CD-9EF9-C850-9G73587DC7C/Documents/XF_Downloads/hausmann_abcd.jpg
path. So at which location file get saved? below is the image for the same.
I have written below code for this
public class IosDownloader : IDownloader
{
public event EventHandler<DownloadEventArgs> OnFileDownloaded;
public void DownloadFile(string url, string folder)
{
string pathToNewFolder = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Personal), folder);
Directory.CreateDirectory(pathToNewFolder);
try
{
WebClient webClient = new WebClient();
webClient.DownloadFileCompleted += new AsyncCompletedEventHandler(Completed);
string pathToNewFile = Path.Combine(pathToNewFolder, Path.GetFileName(url));
webClient.DownloadFileAsync(new Uri(url), pathToNewFile);
}
catch (Exception ex)
{
if (OnFileDownloaded != null)
OnFileDownloaded.Invoke(this, new DownloadEventArgs(false));
}
}
private void Completed(object sender, AsyncCompletedEventArgs e)
{
if (e.Error != null)
{
if (OnFileDownloaded != null)
OnFileDownloaded.Invoke(this, new DownloadEventArgs(false));
}
else
{
if (OnFileDownloaded != null)
OnFileDownloaded.Invoke(this, new DownloadEventArgs(true));
}
}
}
When a file is saved on an application it is a temporary url within the app's sandbox. To make this image file be publicly accessible through Apple's Photos, You'll have to use native code to do a request to add a new PHImageAsset to the photos library.
In forms you would need to access the native frameworks and therefore run native code. There are plenty of examples of doing this online if you don't know how to already. But here is an introduction if you want to run native code within a shared code framework. https://learn.microsoft.com/en-us/xamarin/xamarin-forms/app-fundamentals/dependency-service/introduction
Here is a sample of taking that temp file URL and saving it to Photos Framework once you can code w/ native Xamarin.iOS frameworks:
public void AddImageUrlToPhotosLibrary(string urlToSaveToPhotos)
{
PHPhotoLibrary.SharedPhotoLibrary.PerformChanges(() => {
//This is bound to native https://developer.apple.com/documentation/photokit/phassetchangerequest/1624060-creationrequestforasset
//Parameter is an NSURL of path to image.
PHAssetChangeRequest.FromImage(new NSUrl(urlToSaveToPhotos));
}, (completed, error) => {
if (completed)
{
if (error != null)
{
Console.WriteLine($"Failed saving image asset {error.LocalizedDescription}");
} else
{
Console.WriteLine($"Successfully saved image to photos library.");
}
}
});
}
I am not able to find the downloaded file in my apple device.
If you use a simulator, you can directly find the folder in the mac by entering the path in the
your mac --> select Finder --> Then open the Go menu --> Click Go to Folder as I described in this thread:
Where can I find the MyDocuments folder on iPhone Simulator?
If you installed the app in a real device. You can browse the file in
Xcode --> Devices and Simulators --> download container as described in this thread:
Browse the files created on a device by the iOS application I'm developing, after downloading the container, you can right click it and choose Show Package Contents. Then you can see the folders.
You can also access the file by the path in the project.

How to resolve "Unable to resolve host" error?

I am working on xamarin forms. Where I am consuming the API. When I am running the app in android 5 it is working fine but If I am running 7 + it is giving the error like
Unable to resolve host "almsdev.southeastasia.cloudapp.azure.com": No address associated with hostname.
How to resolve this?
Following is the code snippet:
public async Task<HttpResponseMessage> Login(string EmailOrMobile)
{
try
{
var responseTask = await client.GetAsync(OauthBaseUrl + "OAuthSAAS/MSLogin?UserCredentials=" + EmailOrMobile);
return responseTask;
}
catch (Exception ex)
{
Crashes.TrackError(ex);
return null;
}
}
On button click I am calling above method
private async void fn_Submit_Clicked(object sender, EventArgs e)
{
var response = await _oauthService.Login(txt_credentails.Text.Trim());
}
My Base URL is
http://almsdev.southeastasia.cloudapp.azure.com:81/api/
I am using
Http client = new Http();
Since you are targeting Android 9.0(API level 28) cleartext(non-HTTPS) support is disabled by default.
To overcome this you can: either use HTTPS, or, add configs to allow http traffic.
First, in your Android Project, create a folder: xml and add the file network_security_config
<?xml version="1.0" encoding="utf-8"?>
<network-security-config>
<domain-config cleartextTrafficPermitted="true">
<domain includeSubdomains="true">almsdev.southeastasia.cloudapp.azure.com</domain>
</domain-config>
</network-security-config>
Then, in your Manifest.xml
<application android:label="YourAppName" android:networkSecurityConfig="#xml/network_security_config">
You can read more in the Xamarin Blog Post
Try to Add the login credentials to your Header Http Client.

How do I open an internally created pdf in Xamarin.Android via a FileProvider in the default system pdf app?

I created a .pdf file in the private local directory I got via (I try to work with the minimum of permissions):
string targetBaseDir = Environment.GetFolderPath(
Environment.SpecialFolder.Personal,
Environment.SpecialFolderOption.Create
);
The official Android documentation suggests that file should be shared via a FileProvider.
I also tried to get some code to start an intent, and I'm currently at:
var fileUri = Android.Net.Uri.Parse(filePath);
var intent = new Intent();
intent.SetFlags(ActivityFlags.ClearTop);
intent.SetFlags(ActivityFlags.NewTask);
intent.SetAction(Intent.ActionView);
intent.SetType("application/pdf");
intent.PutExtra(Intent.ExtraStream, fileUri);
intent.AddFlags(ActivityFlags.GrantReadUriPermission);
Android.App.Application.Context.StartActivity(intent);
This starts the share dialog for a pdf file but while the Adobe Pdf reader gets opened it shows an empty view and not my pdf file.
You need to wrap your URI with FileProvider. Since android uri will give you file:// while FileProvider will give you content://, which you actually need:
public static Android.Net.Uri WrapFileWithUri(Context context,Java.IO.File file)
{
Android.Net.Uri result;
if (Build.VERSION.SdkInt < (BuildVersionCodes)24)
{
result = Android.Net.Uri.FromFile(file);
}
else
{
result = FileProvider.GetUriForFile(context, context.ApplicationContext.PackageName + ".provider", file);
}
return result;
}
File can be createed this way:
var file = new Java.IO.File(filePath);
Then you can open it:
public static void View(Context context, string path, string mimeType)
{
Intent viewIntent = new Intent(Intent.ActionView);
Java.IO.File document = new Java.IO.File(path);
viewIntent.SetDataAndType(UriResolver.WrapFileWithUri(context,document),mimeType);
viewIntent.SetFlags(ActivityFlags.NewTask);
viewIntent.AddFlags(ActivityFlags.GrantReadUriPermission);
context.StartActivity(Intent.CreateChooser(viewIntent, "your text"));
}
Be aware, that this line
viewIntent.SetDataAndType(UriResolver.WrapFileWithUri(context,document),mimeType);
does not equal to SetData and SetType separate commands.
And yes, you need to add FileProvider to your manifest:
<provider android:name="android.support.v4.content.FileProvider" android:authorities="${applicationId}.provider" android:exported="false" android:grantUriPermissions="true">
<meta-data android:name="android.support.FILE_PROVIDER_PATHS" android:resource="#xml/provider_paths" />
</provider>
Also you need to create Resources\xml folder with provider_paths.xml file:
<?xml version="1.0" encoding="utf-8"?>
<paths xmlns:android="http://schemas.android.com/apk/res/android">
<external-path name="external_files" path="."/>
<files-path name="internal_files" path="." />
</paths>

Xamarin i cannot turn on Flashlight on version 5.1.1(Samsung) & 4.42(LG G3) [duplicate]

I am currently working on Flashlight On/OFF. I am getting this error java.lang.RuntimeException: Fail to connect to camera service I don't know why this error is occurring. I referred to many solutions but my problem was still not solved. When flashlight is on, the error does not occur but when the flashlight is off then the error occurs.
My Code Main Code.
My Manifest permission:
<uses-permission android:name="android.permission.CAMERA" />
<uses-feature android:name="android.hardware.camera" />
<uses-feature android:name="android.hardware.camera.autofocus"/>
I had the same issue that none of the answers here solved, so after solving it I am adding my way of solving it. This applies to new android versions that support setting permissions per app (since Marshmallow, 6.0). The permission for camera could be disabled and should be enabled from the app settings.
Settings -> Apps -> [Your App] -> Permissions
More info about this here: http://developer.android.com/training/permissions/requesting.html
I also saw this error:
java.lang.RuntimeException: Fail to connect to camera service
while experimenting with a flashlight app. Turns out that I was a bit sloppy with my permissions and copied them into the body of the application block in the manifest.xml file. So you REALLY need to obey the syntax as documented in:
http://developer.android.com/guide/topics/manifest/manifest-element.html
Otherwise the app will fail with service connection failure on the Camera.open() call. It should look like this based on your permissions in the question:
<uses-permission android:name="android.permission.CAMERA" />
<uses-feature android:name="android.hardware.camera" />
<uses-feature android:name="android.hardware.camera.autofocus"/>
<application
Make sure your permission and feature list is contained only in the manifest section, and not buried in the application section!
try this...
static Camera camera = null;
declare it on top.
try{
if(clickOn == true) {
clickOn = false;
camera = Camera.open();
Parameters parameters = camera.getParameters();
parameters.setFlashMode(Parameters.FLASH_MODE_TORCH);
camera.setParameters(parameters);
camera.startPreview();
remoteViews.setViewVisibility(R.id.button1, View.GONE);
remoteViews.setViewVisibility(R.id.button2, View.VISIBLE);
localAppWidgetManager.updateAppWidget(componentName, remoteViews);
} else {
clickOn = true;
camera.stopPreview();
camera.release();
camera = null;
remoteViews.setViewVisibility(R.id.button1, View.VISIBLE);
remoteViews.setViewVisibility(R.id.button2, View.GONE);
localAppWidgetManager.updateAppWidget(componentName, remoteViews);
}
} catch(Exception e) {
Log.e("Error", ""+e);
}
This problem may arise in android 6.0 if you didn't enable camera permission for your app. As from Android 6.0 you can handle the app permission weather you will give or not specific permission for an application.
So, you need to enable permission from settings->apps->your_app->enable camera permission if its not already enabled.
If your os version is 6.0 or later version try this, hope this will help.
public class RequestUserPermission {
private Activity activity;
// Storage Permissions
private static final int REQUEST_EXTERNAL_STORAGE = 1;
private static String[] PERMISSIONS_STORAGE = {
Manifest.permission.READ_EXTERNAL_STORAGE,
Manifest.permission.WRITE_EXTERNAL_STORAGE,
Manifest.permission.CAMERA
};
public RequestUserPermission(Activity activity) {
this.activity = activity;
}
public void verifyStoragePermissions() {
// Check if we have write permission
int permission = ActivityCompat.checkSelfPermission(activity, Manifest.permission.WRITE_EXTERNAL_STORAGE);
if (permission != PackageManager.PERMISSION_GRANTED) {
// We don't have permission so prompt the user
ActivityCompat.requestPermissions(
activity,
PERMISSIONS_STORAGE,
REQUEST_EXTERNAL_STORAGE
);
}
}
}
**//CALL FROM YOUR ACTIVITY**
RequestUserPermission requestUserPermission = new RequestUserPermission(this);
requestUserPermission.verifyStoragePermissions();
if you try to open the camera using a cameraID that does not exist, you will receive that same error (java.lang.RuntimeException: Fail to Connect to camera service)
look at your code at this block
camera.setParameters(parameters);
camera.stopPreview();
camera.release();
camera = null;
Call release() to release the camera for use by other applications. Applications should release the camera immediately in onPause() (and re-open() it in onResume().
In above code imediately after release you are putting null to camera
Hi i hope you are dealing with a torch kind of app or something related to flash and there were many discussions went on this before and here are some useful links and tutorials to achieve your need, please go through them hope they may help you
How to turn on camera flash light programmatically in Android?
http://www.androidhive.info/2013/04/android-developing-flashlight-application/
http://www.compiletimeerror.com/2013/08/how-to-turn-onoff-camera-led-flashlight.html#.U4WH5Xbc3o4
http://android.programmerguru.com/android-flashlight-example/
You need to stopPreview() and release() once you came back from camera,
so that other application can able to access it. Make the "Camera" class as static and refer it as null in onPause(). This resolves my Issue.
Try it out:
public class CameraPhotoCapture extends Activity{
static Camera mcamera = null;
#Override
protected void onPause() {
// TODO Auto-generated method stub
if (mcamera != null) {
mcamera.stopPreview();
mcamera.release();
mcamera = null;
Log.d(DEBUG_TAG, "releaseCamera -- done");
}
super.onPause();
}
#Override
protected void onResume() {
// TODO Auto-generated method stub
if (mcamera != null) {
Camera.open();
Log.d(DEBUG_TAG, "openCamera -- done");
}
super.onResume();
}
}
The simple answer I can find to this problem is I was not asking for camera permission to the user, and that's why by default camera permission was not available to my app on Marshmallow devices. I simply added permission check for the camera before starting the camera and everything works fine.
private boolean checkPermission() {
if (ContextCompat.checkSelfPermission(getApplicationContext(),
android.Manifest.permission.CAMERA) == PackageManager.PERMISSION_GRANTED) {
return true;
}
return false;
}
Check the camera permission at runtime, and request the permission if it has not be granted. It works for me.
if (checkPermission()) {
initCamera();
} else {
ActivityCompat.requestPermissions(this,
new String[]{android.Manifest.permission.CAMERA}, REQUEST_CAMERA_PERMISSION);
}
Try to use this line, when you're exiting the app :
System.exit(0);
I just got a code of an Flashlight app from somewhere. It was using System.exit(0) to close the app. I removed it, knowing that this is not a good practice. Then I started to receive these errors. I tried the solution of the accepted answer, but then I started receiving some other errors. So, instead of solving them I just put this System.exit(0) line back. And, it started working fine. I know this is not a good way, but for a small flashlight app, you can try this quick solution.
Set the Required permission in Mainfest file.
Ask the Permission to accept the Camera.
It will work for me
If all your code is ok, you should check are there any other application using your camera. Then you should close other application that currently using your camera.
In my android peoject has the same issue. This is my Logcat error
03-29 19:26:04.194 224-608/? V/EmulatedCamera_BaseCamera:
getCameraInfo 03-29 19:26:04.196 224-224/? I/CameraService:
CameraService::connect call (PID -1 "com.proitzen.staffapp", camera ID
1) for HAL version default and Camera API version 1 03-29 19:26:04.196
224-224/? W/ServiceManager: Permission failure:
android.permission.CAMERA from uid=10067 pid=1776 03-29 19:26:04.196
224-224/? E/CameraService: Permission Denial: can't use the camera
pid=1776, uid=10067 03-29 19:26:04.196 1776-1776/com.proitzen.staffapp
W/CameraBase: An error occurred while connecting to camera 1: Service
not available 03-29 19:26:04.200 1776-1776/com.proitzen.staffapp
D/AndroidRuntime: Shutting down VM
No any above solutions worked for me. My android app worked in physical android devices and gave the above error only in Genymotion.
Solution : start your Genumotion emulator
Settings --> Apps ---> choose your App --> Permissions --> enable camera and Mic and storage.

Geo location is not working in xamarin android

I am try to get the current geo location of the phone using 'plugin.geolocator' but it works fine in ios in android getting task cancellation exception. Here is the code I have tried. Please suggest any idea why I am getting this exception.
sample code:
var locator = CrossGeolocator.Current;
locator.DesiredAccuracy = -1;
if (locator.IsGeolocationEnabled)
{
var position = await locator.GetPositionAsync(TimeSpan.FromMilliseconds(5000));
}
These are the permissions I have gave in android manifest file.
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
I am getting task cancellation exception while I am testing in emulator. I have tried with changing time span but no luck getting task cancellation exception only.
Set a different value for Desired accuracy (big values -> more chance to have a result):
locator.DesiredAccuracy = 100;
Well, you also have to override OnRequestPermissionResult on your MainActivity class:
public override void OnRequestPermissionsResult(int requestCode, string[] permissions, Permission[] grantResults)
{
PermissionsImplementation.Current.OnRequestPermissionsResult(requestCode, permissions, grantResults);
}
And ensure your Android Target version is API 25+. See https://jamesmontemagno.github.io/GeolocatorPlugin/GettingStarted.html

Resources