Having problems saving camera images - image

I have been through the contents and cant seem to find an answer to my issue.
I have an imagefile in my app, and a button... I am following the tutorial on android developers https://developer.android.com/training/camera/photobasics#java but am having problems saving the file. At one point, I was able to save to cache, but i would rather save to a folder in pictures.
Here is my code...
static final int REQUEST_IMAGE_CAPTURE = 1;
private void dispatchTakePictureIntent() {
Intent dispatchTakePictureIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
// Ensure that there's a camera activity to handle the intent
if (dispatchTakePictureIntent.resolveActivity(getPackageManager()) != null) {
// Create the File where the photo should go
File photoFile = null;
photoFile = createImageFile();
// Continue only if the File was successfully created
if (photoFile != null) {
Uri photoURI = FileProvider.getUriForFile(this,
"com.example.ConfinedSpaceManagement",
photoFile);
dispatchTakePictureIntent.putExtra(MediaStore.EXTRA_OUTPUT, photoURI);
startActivityForResult(dispatchTakePictureIntent, REQUEST_TAKE_PHOTO);
}
}
}
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (requestCode == REQUEST_IMAGE_CAPTURE && resultCode == RESULT_OK) {
Bundle extras = data.getExtras();
Bitmap imageBitmap = (Bitmap) extras.get("data");
imageView.setImageBitmap(imageBitmap);
}
}
String currentPhotoPath;
private File createImageFile(){
// Create an image file name
File storageDir = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES);
if (!storageDir.exists()) {
if (!storageDir.mkdirs()) {
Log.d("Confined_Space", "failed to create Directory");
return null;
}
}
String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date());
return new File(storageDir.getPath() + File.separator + "ConSp" + timeStamp + ".jpg");
}
//String imageFileName = "JPEG_" + timeStamp + "_";
////////////////////////////////////////////////////////////////
static final int REQUEST_TAKE_PHOTO = 1;
}
and this is my manifest
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.confinedspacemanagement">
<uses-feature android:name="android.hardware.camera"
android:required="false" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"
android:maxSdkVersion="18" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<application
android:allowBackup="true"
android:icon="#mipmap/ic_launcher"
android:label="#string/app_name"
android:roundIcon="#mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="#style/AppTheme">
<meta-data
android:name="com.google.android.actions"
android:resource="#xml/file_paths" />
<activity android:name=".Signature" />
<activity android:name=".AuditWork" />
<activity android:name=".DisplayIndividual" />
<activity android:name=".SecondActivity" />
<activity android:name=".Definition" />
<activity
android:name=".MainActivity"
android:screenOrientation="portrait">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<provider
android:name="androidx.core.content.FileProvider"
android:authorities="com.example.confinedspacemanagement.fileprovider"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="#xml/file_paths"/>
</provider>
</application>
</manifest>
and here is my xml.file_path
<?xml version="1.0" encoding="utf-8"?>
<paths xmlns:android="http://schemas.android.com/apk/res/android">
<external-path name="my_images" path="Android/data/com.example.package.name/files/Pictures" />
</paths>
The activity is a sqlite form page. I am trying to take a picture, save it to a specified file, and then save the file path into the database.
Any help out there??? Should I be using camera2???

I found an answer at https://www.youtube.com/watch?v=VqgZxiU2knM by Mr. PRABEESH R K.
The image is saving fine, but I am taking the picture from an activity that is not the main activity. When I return the result, the page goes back to main activity, not the page the camera was originally requested from. Is there any way to keep it on the sending page?

Related

Access to the path is denied Xamarin forms

I am trying to copy my db file to internal storage root/document. My codes are working good till Android 9 but after it i am getting the error "System.UnauthorizedAccessException: Access to the path "/storage/emulated/0/Documents/FruitsApp/Backup/Fruits.db_2021-06-28 12:20:20" is denied"
I have try lots of way to copy all are working before Android 9 but after it i am getting above error. I am sharing my all codes. Thanks in advance.
----copy code
Java.IO.File mediaStorageDir = new Java.IO.File(Android.OS.Environment.GetExternalStoragePublicDirectory(Android.OS.Environment.DirectoryDocuments) + path);
if (!mediaStorageDir.Exists())
{
var tt = mediaStorageDir.Mkdirs();
if (mediaStorageDir.Mkdirs() == false)
{
var fail = "failed to create";
}
}
var directoryPath = mediaStorageDir.AbsolutePath;
////////--this way to create folder is working till andorid 9
//var PathExists = Directory.Exists(directoryPath);
//if (PathExists ==false)
//{
// Directory.CreateDirectory(directoryPath);
//}
var dbPath = Path.Combine(System.Environment.GetFolderPath(System.Environment.SpecialFolder.Personal), "Fruits.db");
FileInfo file = new FileInfo(dbPath);
var dbName = file.Name;
var fullFileName = string.Concat("/", dbName + "_", Global.CurrentDateTime());
var newpath = string.Format("{0}{1}", directoryPath, fullFileName);
//////--- First way copy file from source to destination is working tille android 9
//using (FileStream sourceStream = System.IO.File.Open(dbPath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
//using (FileStream destinationStream = System.IO.File.Create(newpath))
//{
// sourceStream.CopyToAsync(destinationStream);
//}
//////--- 2nd way copy file from source to destination is working tille android 9
byte[] dbFile = System.IO.File.ReadAllBytes(dbPath);
System.IO.File.WriteAllBytes(newpath, dbFile);
//////--- 3rd way copy file from source to destination is working tille android 9
//file.CopyTo(newpath);
I have try 3 ways to copy file from source to another all ways are working till android 9 but not working after android 9.
--Android Manifest file
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android" android:versionCode="1"
android:versionName="1.0" package="com.NewWave.FruitApp" android:installLocation="auto">
<uses-sdk android:minSdkVersion="23" android:targetSdkVersion="30" />
<application android:requestLegacyExternalStorage="true" android:label="FruitApp"
android:theme="#style/MainTheme"></application>
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.CALL_PHONE" />
<uses-permission android:name="android.permission.SEND_SMS" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"
android:maxSdkVersion="29" />
<uses-permission android:name="android.permission.ACCESS_MEDIA_LOCATION" />
<!--<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />-->
</manifest>
I have a SQLite database saved in the internal storage of my cellphone, in a folder created folder named SQLite. I had troubles with the permissions and the path. Here's how I solved it:
private readonly SQLiteAsyncConnection _conn;
public LocalContext()
{
// Create directory for SQLite
Directory.CreateDirectory(Path.Combine("/storage/emulated/0/","SQLite"));
string dbPath = Path.Combine(
"/storage/emulated/0/SQLite",
"ventaMovil.db");
_conn = new SQLiteAsyncConnection(dbPath);
}
Before I called my LocalContext I check if you have writing permissions:
private async Task<bool> CheckPermissions()
{
var status = await _permissionService.CheckAndRequestPermissionAsync(new Permissions.StorageWrite());
if (status != PermissionStatus.Granted)
{
await App.Current.MainPage.DisplayAlert("Error", "You do not have writing permissions", "Okay");
return false;
}
return true;
}
For the permissions I use Xamarin Essentials:
public class PermissionService : IPermissionService
{
public async Task<PermissionStatus> CheckAndRequestPermissionAsync<T>(T permission) where T : Permissions.BasePermission
{
var status = await permission.CheckStatusAsync();
if (status != PermissionStatus.Granted)
{
status = await permission.RequestAsync();
}
return status;
}
}
And in the Android Manifest I have these two:
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />

How to persist a choice in a Xamarin Android alert dialog

This dialog box displays correctly, except that the user's choice is not captured:
var dialogView = LayoutInflater.Inflate(Resource.Layout.list_view, null);
Android.App.AlertDialog alertDialog;
var items = new string[] { "A","B","C" };
var adapter = new ArrayAdapter<string>(this, Android.Resource.Layout.SimpleListItem1, items);
using (var dialog = new Android.App.AlertDialog.Builder(this))
{
dialog.SetTitle("Choose Letter");
dialog.SetMessage("Just Click!");
dialog.SetView(dialogView);
dialog.SetNegativeButton("Cancel", (s, a) => { });
dialog.SetPositiveButton("OK", (s, a) => {
{
if (a.Which!=-1)
//BUT I don't know how to persist the choice
//when I click on one of the letters, it briefly
//shows the choice (the background is briefly grayed
//but the choice doesn't persist
//so when I click OK, a.Which is -1
{
//do things with the choice
}
}});
alertDialog = dialog.Create();
}
dialogView.FindViewById<ListView>(Resource.Id.listview).Adapter = adapter;
alertDialog.Show();
}
And this is the axml:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<ListView
android:id="#+id/listview"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
</LinearLayout>
How do I 1) show the user's choice more than the line being briefly grayed and 2) how do I persist that choice?
Do you want to achieve the result like following GIF?
If so, you can create a ListItem to replace the Android.Resource.Layout.SimpleListItem1
Here is my ListItem
var adapter = new ArrayAdapter<string>(this, Resource.Layout.list_item, items);
list_item
<?xml version="1.0" encoding="utf-8" ?>
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#android:id/text1"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#drawable/mybackground"
android:gravity="center_vertical"
android:padding="3dp"
android:textSize="20sp"
/>
mybackground
<?xml version="1.0" encoding="utf-8" ?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="#android:color/background_light"
android:state_pressed="false" android:state_selected="false"/>
<item android:drawable="#android:color/background_dark"
android:state_pressed="true"/>
<item android:drawable="#color/light_blue" android:state_pressed="false"
android:state_selected="true"/>
And achieve the listview.ItemClick += Listview_ItemClick;
private void Listview_ItemClick(object sender, AdapterView.ItemClickEventArgs e)
{
e.View.Selected = true;
}
Here is my demo.
https://github.com/851265601/Xamarin.Android_ListviewSelect

not getting how to use incoming image from android chooser intent

I'm trying to display the image in main page. the image will come from whats app profile upon sharing that image to my app.
app.js
if (intent.getClipData()) {
let imageUri = intent.getClipData().getItemAt(0).getUri()
console.log(imageUri);
// content://com.whatsapp.fileprovider/external/WhatsApp/.Shared/photo.jpg
global.imageUri = imageUri;
}
xml
<StackLayout class="p-20">
<Image src="{{ imageUri }}" stretch="none" />
</StackLayout>
viewModel
imageUri: global.imageUri,
getting this error
Error in downloadBitmap - java.net.MalformedURLException: Unknown protocol: content
i need to know how to use incoming images from intent services of android.
add these things in android manifest
<intent-filter>
<action android:name="android.intent.action.SEND" />
<category android:name="android.intent.category.DEFAULT" />
<data android:mimeType="image/*" />
</intent-filter>
<intent-filter>
<action android:name="android.intent.action.SEND" />
<category android:name="android.intent.category.DEFAULT" />
<data android:mimeType="text/plain" />
</intent-filter>
<intent-filter>
<action android:name="android.intent.action.SEND_MULTIPLE" />
<category android:name="android.intent.category.DEFAULT" />
<data android:mimeType="image/*" />
</intent-filter>
to handle it copy paste this code anywhere you like
if (platform_1.isAndroid) {
application.android.on(application.AndroidApplication.activityCreatedEvent, function (args) {
var activity = args.activity;
// Get intent, action and MIME type
var intent = activity.getIntent();
var action = intent.getAction();
var type = intent.getType();
if (android.content.Intent.ACTION_SEND === action && type != null) {
if (type.startsWith("text/")) {
handleSendText(intent); // Handle text being sent
}
else if (type.startsWith("image/")) {
handleSendImage(intent); // Handle single image being sent
}
}
else if (android.content.Intent.ACTION_SEND_MULTIPLE === action && type != null) {
if (type.startsWith("image/")) {
handleSendMultipleImages(intent); // Handle multiple images being sent
}
}
else {
// Handle other intents, such as being started from the home screen
}
});
}
function handleSendText(intent) {
if (platform_1.isAndroid) {
var sharedText = intent.getStringExtra(android.content.Intent.EXTRA_TEXT);
if (sharedText != null) {
// Update UI to reflect text being shared
console.log("sharedText: ", sharedText);
console.log("Text received!");
vm.set("sharedText", sharedText);
}
}
}
function handleSendImage(intent) {
if (platform_1.isAndroid) {
var imageUri = intent.getParcelableExtra(android.content.Intent.EXTRA_STREAM);
if (imageUri != null) {
// Update UI to reflect image being shared
console.log("Image received!");
var appContext = application.android.context;
var bitmap = android.provider.MediaStore.Images.Media.getBitmap(appContext.getContentResolver(), imageUri);
console.log("bitmap: ", bitmap);
vm.set("bitmap", bitmap);
}
}
}
function handleSendMultipleImages(intent) {
if (platform_1.isAndroid) {
var imageUris = intent.getParcelableArrayListExtra(android.content.Intent.EXTRA_STREAM);
if (imageUris != null) {
// Update UI to reflect multiple images being shared
console.log("imageUris: ", imageUris);
console.log("Multiple images received!");
}
}
}
You can not directly display image using content uri. You will have to parse the actual file url using MediaStore
You may refer the source code of nativescript-imagepicker for working sample. It returns the actual file path after parsing the content uri when you a image is selected from gallery.

Xamarin: How to change Stepper color in Android to look like in iOS?

I have Xamarin PCL app which uses Stepper. I wanted to change the color of my Stepper button and now using the following renderer.
In PCL:
public class MyStepper : Stepper
{
public static readonly BindableProperty ColorProperty =
BindableProperty.Create(nameof(Color), typeof(Color), typeof(MyStepper), Color.Default);
public Color MyColor
{
get { return (Color)GetValue(ColorProperty); }
set { SetValue(ColorProperty, value); }
}
}
In iOS:
public class MyStepperRenderer : StepperRenderer
{
protected override void OnElementChanged(ElementChangedEventArgs<Stepper> e)
{
base.OnElementChanged(e);
MyStepper s = Element as MyStepper;
if (Control != null)
Control.TintColor = s.MyColor.ToUIColor();
}
}
In Android:
protected override void OnElementChanged(ElementChangedEventArgs<Stepper> e)
{
base.OnElementChanged(e);
MyStepper s = Element as MyStepper;
if (Control != null)
{
Control.GetChildAt(0).Background.SetColorFilter(s.MyColor.ToAndroid(), PorterDuff.Mode.Multiply);
Control.GetChildAt(1).Background.SetColorFilter(s.MyColor.ToAndroid(), PorterDuff.Mode.Multiply);
}
}
In XAML:
<local:MyStepper MyColor="Red" Maximum="10" Minimum="0" ....... />
As expected it would work like the images attached. But is it possible to make the Android color to change just the "outline" of the button like what it looks like in iOS?
How about changing the colors of the - and + also to red. Is there a way to do that also?
Based on #Sven-Michael Stübe's answer, I add some code to change the "-" and "+" color:
protected override void OnElementChanged(ElementChangedEventArgs<Stepper> e)
{
base.OnElementChanged(e);
MyStepper s = Element as MyStepper;
if (Control != null)
{
var button = Control.GetChildAt(0) as Android.Widget.Button;
button.SetTextColor(s.MyColor.ToAndroid());
button.SetBackground(ResourcesCompat.GetDrawable(Resources, Resource.Drawable.button_selector, null));
button.Background.SetColorFilter(s.MyColor.ToAndroid(), PorterDuff.Mode.Multiply);
var button2 = Control.GetChildAt(1) as Android.Widget.Button;
button2.SetTextColor(s.MyColor.ToAndroid());
button2.SetBackground(ResourcesCompat.GetDrawable(Resources, Resource.Drawable.button_selector, null));
button2.Background.SetColorFilter(s.MyColor.ToAndroid(), PorterDuff.Mode.Multiply);
}
}
Effectt.
go and create a the drawable with the states and set them in your Renderer instead of setting a single color.
Sven-Michael Stübe wanna say that if you set a single color as a background, then your Button will have no click effect. You could refer to: Material effect on button with background color
for more detail information.
For example:
button_selector.xml:
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="#color/colorAccent" android:state_pressed="true"/>
<item android:drawable="#color/colorPrimaryDark" android:state_focused="true"/>
<item android:drawable="#drawable/button_border"/>
</selector>
button_border.xml:
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle" >
<solid android:color="#00FFFFFF" />
<corners android:radius="5dp" />
<stroke
android:width="2dp"
android:color="#FFFFFF" />
</shape>
You can do it if you create a custom vector drawable
button_border.xml
Place this file in your Android Resources\drawable folder and ensure the build action is set to AndroidResource
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle" >
<solid android:color="#00FFFFFF" />
<corners android:radius="5dp" />
<stroke
android:width="2dp"
android:color="#FFFFFF" />
</shape>
MyStepperRenderer.cs
Then you just need to set it as background of your two buttons.
protected override void OnElementChanged(ElementChangedEventArgs<Stepper> e)
{
base.OnElementChanged(e);
var s = Element as MyStepper;
if (Control != null)
{
Control.GetChildAt(0).SetBackground(Resources.GetDrawable(Resource.Drawable.button_border));
Control.GetChildAt(1).SetBackground(Resources.GetDrawable(Resource.Drawable.button_border));
Control.GetChildAt(0).Background.SetColorFilter(s.MyColor.ToAndroid(), PorterDuff.Mode.Multiply);
Control.GetChildAt(1).Background.SetColorFilter(s.MyColor.ToAndroid(), PorterDuff.Mode.Multiply);
}
}
This will look like:
discussion
You loose states like pressed, disabled, ... (see https://developer.android.com/guide/topics/resources/color-list-resource.html)
If you don't have many different colors, go and create a the drawable with the states and set them in your Renderer instead of setting a single color. So your user will get a better feedback.

Android: Make custom seekbar opaque

Hi can anyone tell me why is my Seekbar's background and progress always have some opacity and just can't be removed even I have set the alpha to 1.0. Below is my progress_drawable.xml
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item android:id="#android:id/background">
<shape>
<corners android:radius="5dip" />
<gradient
android:alpha="1.0"
android:startColor="#000000"
android:endColor="#000000"/>
</shape>
</item>
<item android:id="#android:id/secondaryProgress">
<clip>
<shape>
<corners android:radius="5dip" />
<gradient
android:alpha="1.0"
android:startColor="#000000"
android:endColor="#000000" />
</shape>
</clip>
</item>
<item android:id="#android:id/progress">
<clip>
<shape>
<corners android:radius="5dip" />
<gradient
android:alpha="1.0"
android:endColor="#2e2dff"
android:startColor="#2e2dff" />
<solid android:color="#2e2dff" />
</shape>
</clip>
</item>
And this is the SeekBar tag in activity xml:
<SeekBar
android:padding="0dp"
android:id="#+id/normalSeekbar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="#+id/imgPenguin"
android:alpha="1"
android:progress="0"
android:progressDrawable="#drawable/progress_drawable"
android:secondaryProgress="0" />
I got this result but I want the bars to be opaque, please advise and thanks in advanced.
Just found the issue:
normalSB.setEnabled(false);
I shouldn't use setEnabled(false) to avoid user drag on thumb, instead, I have done this to reset progress when fromUser == true:
normalSB.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
int originalProgress;
#Override
public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
float seekBarStarting = seekBar.getX();
float seekBarWidth = seekBar.getWidth();
float seekBarOffset = seekBar.getThumbOffset();
float ratio = (float) progress / seekBar.getMax();
float scaledProgress = ratio * seekBarWidth;
if (scaledProgress > imgPenguin.getWidth()) {
imgPenguin.setX(seekBarStarting - imgPenguin.getWidth() + scaledProgress);
}
if (fromUser == true) {
seekBar.setProgress(originalProgress);
}
}
#Override
public void onStartTrackingTouch(SeekBar seekBar) {
originalProgress = seekBar.getProgress();
}
#Override
public void onStopTrackingTouch(SeekBar seekBar) {
}
});

Resources