Is there a way to use the camera functions in Xamarin Forms without downloading any extra NuGet Packages? - xamarin.forms

I am currently building a project which allows the user to take a photo of something and use that photo. I was wondering if there were any other methods out there that does not require me to download any Plugins or NuGet Packages?

You need to create a ICameraPickerService in Xamarin Forms :
public interface IPhotoPickerService
{
Task<byte[]> GetImageStreamAsync();
}
In iOS , create the CameraPickerService :
[assembly: Dependency(typeof(CameraPickerService))]
namespace DependencyServiceDemos.iOS
{
public class CameraPickerService: ICameraPickerService
{
TaskCompletionSource<byte[]> taskCompletionSource;
UIImagePickerController imagePicker;
public Task<byte[]> GetImageStreamAsync()
{
// Create and define UIImagePickerController
imagePicker = new UIImagePickerController
{
SourceType = UIImagePickerControllerSourceType.Camera,
MediaTypes = UIImagePickerController.AvailableMediaTypes(UIImagePickerControllerSourceType.Camera)
};
// Set event handlers
imagePicker.FinishedPickingMedia += OnImagePickerFinishedPickingMedia;
imagePicker.Canceled += OnImagePickerCancelled;
// Present UIImagePickerController;
UIWindow window = UIApplication.SharedApplication.KeyWindow;
var viewController = window.RootViewController;
viewController.PresentModalViewController(imagePicker, true);
// Return Task object
taskCompletionSource = new TaskCompletionSource<byte[]>();
return taskCompletionSource.Task;
}
void OnImagePickerFinishedPickingMedia(object sender, UIImagePickerMediaPickedEventArgs args)
{
UIImage image = args.EditedImage ?? args.OriginalImage;
if (image != null)
{
// Convert UIImage to .NET Stream object
NSData data;
if (args.ReferenceUrl.PathExtension.Equals("PNG") || args.ReferenceUrl.PathExtension.Equals("png"))
{
data = image.AsPNG();
}
else
{
data = image.AsJPEG(1);
}
Stream stream = data.AsStream();
UnregisterEventHandlers();
// Set the Stream as the completion of the Task
taskCompletionSource.SetResult(data.ToArray());
}
else
{
UnregisterEventHandlers();
taskCompletionSource.SetResult(null);
}
imagePicker.DismissModalViewController(true);
}
void OnImagePickerCancelled(object sender, EventArgs args)
{
UnregisterEventHandlers();
taskCompletionSource.SetResult(null);
imagePicker.DismissModalViewController(true);
}
void UnregisterEventHandlers()
{
imagePicker.FinishedPickingMedia -= OnImagePickerFinishedPickingMedia;
imagePicker.Canceled -= OnImagePickerCancelled;
}
}
}
Not forgetting to add permission in Info.plist :
<key>NSCameraUsageDescription</key>
<string>Use Camera</string>
In addition , iOS need to run in a physical device.
In Android , create the CameraPickerService :
[assembly: Dependency(typeof(CameraPickerService))]
namespace DependencyServiceDemos.Droid
{
public class CameraPickerService : ICameraPickerService
{
public Task<byte[]> GetImageStreamAsync()
{
// Define the Intent for getting images
Intent getImageByCamera = new Intent("android.media.action.IMAGE_CAPTURE");
// Start the camera (resumes in MainActivity.cs)
MainActivity.Instance.StartActivityForResult(
getImageByCamera,
MainActivity.PickImageId);
// Save the TaskCompletionSource object as a MainActivity property
MainActivity.Instance.PickImageTaskCompletionSource = new TaskCompletionSource<byte[]>();
// Return Task object
return MainActivity.Instance.PickImageTaskCompletionSource.Task;
}
}
}
Adding permission in AndroidMainfest.xml :
<uses-permission android:name= "android.permission.CAMERA" />
<uses-permission android:name= "android.permission.WRITE_EXTERNAL_STORAGE" />
Get Image data in MainActivity :
public class MainActivity : global::Xamarin.Forms.Platform.Android.FormsAppCompatActivity
{
internal static MainActivity Instance { get; private set; }
public int CAMERA_JAVA_REQUEST_CODE = 1;
protected override void OnCreate(Bundle savedInstanceState)
{
TabLayoutResource = Resource.Layout.Tabbar;
ToolbarResource = Resource.Layout.Toolbar;
base.OnCreate(savedInstanceState);
Instance = this;
global::Xamarin.Forms.Forms.Init(this, savedInstanceState);
LoadApplication(new App());
DependencyService.Register<ITextToSpeechService, TextToSpeechService>();
}
// Field, property, and method for Picture Picker
public static readonly int PickImageId = 1000;
public TaskCompletionSource<byte[]> PickImageTaskCompletionSource { set; get; }
protected override void OnActivityResult(int requestCode, Result resultCode, Intent intent)
{
base.OnActivityResult(requestCode, resultCode, intent);
if (requestCode == PickImageId)
{
if ((resultCode == Result.Ok) && (intent != null))
{
Bundle bundle = intent.Extras;
Bitmap bitmap = (Bitmap)bundle.Get("data");
//// Set the Stream as the completion of the Task
MemoryStream memoryStream = new MemoryStream();
bitmap.Compress(Bitmap.CompressFormat.Jpeg, 50, memoryStream);
PickImageTaskCompletionSource.SetResult(memoryStream.ToArray());
}
else
{
PickImageTaskCompletionSource.SetResult(null);
}
}
}
}
Finally , show image in ContentPage of Forms :
async void OnPickPhotoButtonClicked(object sender, EventArgs e)
{
(sender as Button).IsEnabled = false;
byte[] data = await DependencyService.Get<IPhotoPickerService>().GetImageStreamAsync();
MemoryStream stream = new MemoryStream(data);
if (stream != null)
{
image.Source = ImageSource.FromStream(() => stream) ;
}
(sender as Button).IsEnabled = true;
}
The effect :
Note : If want to pick a Photo from the Picture Library, you can have a look at this official document .

Related

Xamarin.Android : Problem using the library Zxing,Net.Mobile, error (Message=Resource ID #0x7f0a002a) in the debug before inflate the AXML

I have a problem using the library Zxing,Net.Mobile, want to have a popup (fragment) which reads a barcode, but in debug I get an error, I'm using the following repository as an example (https://github.com/Redth/ZXing.Net.Mobile/tree/master/Samples/Sample.Android), but when I run the code and click to open the fragment I get the following problem.
This is my AXML Activity (OrdersPatientsActivity)
When I click on the red highlighted button, it opens my popup (ScanBarcodeFragment), but in the Activity I initialise Zxing as follows (the final part):
{
base.OnCreate(savedInstanceState);
// Create your application here
SetContentView(Resource.Layout.LayoutListOrdenPatient);
searchBar = FindViewById<EditText>(Resource.Id.searchBarMainFilterCarMed);
llPatientInfo = FindViewById<LinearLayout>(Resource.Id.llPatientInfo);
PatientName = FindViewById<TextView>(Resource.Id.tvPatientNameCarMed);
IdentificationType = FindViewById<TextView>(Resource.Id.tvTDocumentoCarMed);
Identification = FindViewById<TextView>(Resource.Id.tvDocumentoCarMed);
Age = FindViewById<TextView>(Resource.Id.tvEdadCarMed);
HistoryNumber = FindViewById<TextView>(Resource.Id.tvHistoriaCarMed);
EntryNumber = FindViewById<TextView>(Resource.Id.tvNoIngresoCarMed);
Location = FindViewById<TextView>(Resource.Id.tvUbicacionCarMed);
btnExpandView = FindViewById<ImageButton>(Resource.Id.btnExpandView);
btnScanMed = FindViewById<ImageButton>(Resource.Id.btnScanMed);
ListMedicamentCarMed = FindViewById<ListView>(Resource.Id.ListMedicamentCarMed);
Save = FindViewById<Button>(Resource.Id.btnGuardar);
///vista cargando
var ProgressView = LayoutInflater.Inflate(Resource.Layout.LoadingDialogCharge, null);
TextView Msg = ProgressView.FindViewById<TextView>(Resource.Id.tvProgressDialogMsg);
Msg.Text = "Cargando informaciĆ³n de los cargos...";
animationscale = AnimationUtils.LoadAnimation(this, Resource.Drawable.Animationlogo);
LogoDialogProgress = ProgressView.FindViewById<ImageView>(Resource.Id.LogoDialogProgress);
progressDialog = (new AlertDialog.Builder(this, Resource.Style.ServinteDialog)).Create();
progressDialog.SetView(ProgressView);
Xamarin.Essentials.Platform.Init(this, savedInstanceState);
global::Xamarin.Forms.Forms.Init(this, savedInstanceState);
ZXing.Net.Mobile.Forms.Android.Platform.Init();
ZXing.Mobile.MobileBarcodeScanner.Initialize(Application);
btnScanMed.Click += BtnScanMed_Click;
}
Xamarin.Essentials.Platform.Init(this, savedInstanceState);
global::Xamarin.Forms.Forms.Init(this, savedInstanceState);
ZXing.Net.Mobile.Forms.Android.Platform.Init();
ZXing.Mobile.MobileBarcodeScanner.Initialize(Application);
And in the click the ImageView is this:
try
{
StartActivity(typeof(ScanBarcodeFragment));
}
the fragment is exactly as in the example:
using Android.App;
using Android.Content;
using Android.Content.PM;
using Android.OS;
using Android.Runtime;
using Android.Util;
using Android.Views;
using Android.Widget;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using ZXing.Mobile;
namespace APPDroid.CarMed.Fragments
{
[Activity(Label = "ZXing.Net.Mobile", Theme = "#style/Theme.AppCompat.Light", ConfigurationChanges = ConfigChanges.Orientation | ConfigChanges.KeyboardHidden)]
public class ScanBarcodeFragment : AndroidX.Fragment.App.FragmentActivity
{
#region Variables
ZXingScannerFragment scanFragment;
#endregion
protected override void OnCreate(Bundle savedInstanceState)
{
base.OnCreate(savedInstanceState);
SetContentView(Resource.Layout.ScanBarcode);
}
protected override void OnResume()
{
base.OnResume();
if (scanFragment == null)
{
scanFragment = new ZXingScannerFragment();
SupportFragmentManager.BeginTransaction().Replace(Resource.Id.fragment_container, scanFragment).Commit();
}
Scan();
}
public override void OnRequestPermissionsResult(int requestCode, string[] permissions, Permission[] grantResults)
=> Xamarin.Essentials.Platform.OnRequestPermissionsResult(requestCode, permissions, grantResults);
protected override void OnPause()
{
scanFragment?.StopScanning();
base.OnPause();
}
void Scan()
{
var opts = new MobileBarcodeScanningOptions
{
PossibleFormats = new List<ZXing.BarcodeFormat> {
ZXing.BarcodeFormat.QR_CODE
},
CameraResolutionSelector = availableResolutions =>
{
foreach (var ar in availableResolutions)
{
Console.WriteLine("Resolution: " + ar.Width + "x" + ar.Height);
}
return null;
}
};
scanFragment.StartScanning(result =>
{
// Null result means scanning was cancelled
if (result == null || string.IsNullOrEmpty(result.Text))
{
Toast.MakeText(this, "Scanning Cancelled", ToastLength.Long).Show();
return;
}
// Otherwise, proceed with result
RunOnUiThread(() => Toast.MakeText(this, "Scanned: " + result.Text, ToastLength.Short).Show());
}, opts);
}
}
}
But I get this error when I click on it:
when inflating the view all goes well, but when finishing the Scan() method; the problem occurs:
Android.Content.Res.Resources+NotFoundException Message=Resource ID #0x7f0a002a
Is it possible that I need an extra textview with a result ID?
Please I need help I have been trying to do barcode scanning for several days.

How to make phone calls using Xamairn forms?

I'm new in xamarin and I want make a phone call directly (without opening the dialler). I tried with this example but it doesn't work.
Click Please help
public class PhoneCall_Droid : IPhoneCall
{
public void MakeQuickCall(string PhoneNumber)
{
try
{
var uri = Android.Net.Uri.Parse(string.Format("tel:{0}", PhoneNumber));
var intent = new Intent(Intent.ActionCall, uri);
Xamarin.Forms.Forms.Context.StartActivity(intent);
}
catch (Exception ex)
{
new AlertDialog.Builder(Android.App.Application.Context).SetPositiveButton("OK", (sender, args) =>
{
//User pressed OK
})
.SetMessage(ex.ToString())
.SetTitle("Android Exception")
.Show();
}
}
}
there are two error in your code above:
1.Xamarin.Forms.Forms.Context could not get the correct context.
you could defined a static variable in MainActiviy like :
public static MainActivity Instance;
protected override void OnCreate(Bundle savedInstanceState)
{
TabLayoutResource = Resource.Layout.Tabbar;
ToolbarResource = Resource.Layout.Toolbar;
base.OnCreate(savedInstanceState);
global::Xamarin.Forms.Forms.Init(this, savedInstanceState);
Instance = this;
LoadApplication(new App());
}
you also could use the Current Activity Plugin,you could refer to Current Activity
2.After Android6.0 you should requests the runtime permissions and the official doucument
here is a simple example:
[assembly: Xamarin.Forms.Dependency(typeof(PhoneCall_Droid))]
namespace App18.Droid
{
class PhoneCall_Droid: IPhoneCall
{
public void MakeQuickCall(string PhoneNumber)
{
try
{
if(ActivityCompat.CheckSelfPermission(MainActivity.Instance, Android.Manifest.Permission.CallPhone) != Android.Content.PM.Permission.Granted ){
ActivityCompat.RequestPermissions(MainActivity.Instance, new string[] {Android.Manifest.Permission.CallPhone }, 1);
return;
}
else
{
var uri = Android.Net.Uri.Parse(string.Format("tel:{0}", PhoneNumber));
var intent = new Intent(Intent.ActionCall, uri);
MainActivity.Instance.StartActivity(intent);
}
}
catch (Exception ex)
{
new AlertDialog.Builder(MainActivity.Instance).SetPositiveButton("OK", (sender, args) =>
{
//User pressed OK
})
.SetMessage(ex.ToString())
.SetTitle("Android Exception")
.Show();
}
}
}
}
and you also could to use the nugetpackage Plugin.Permissions to request runtime permissions(Permission.Location)
refer to Plugin.Permissions
finally you could call like
DependencyService.Get<IPhoneCall>().MakeQuickCall(phonenumber);

Custom Keyboard in Xamarin forms

I've read the many posts on the forum and on StackOverflow and other places on making custom keyboards, but have not found an approach that will work for my Xamarin forms cross-platform project. It is programmatically generated.
For example, I built this keyboard that was recommended in several places:
I try to integrate this into my Xamarin forms app but not able to do this
https://github.com/Vaikesh/CustomKeyboard/blob/master/CustomKeyboard/Activity1.cs
It works fine as a standalone
I want Hebrew language keyboard in my application Like this
I would appreciate any help.
Thank you.
Custom Keyboard in Xamarin forms
You could create a PageRenderer and use native .axml layout file to create the custom Keyboard.
For example, my KeyboardPageRenderer :
[assembly: ExportRenderer(typeof(MyKeyboardPage), typeof(KeyboardPageRenderer))]
...
public class KeyboardPageRenderer : PageRenderer
{
public CustomKeyboardView mKeyboardView;
public EditText mTargetView;
public Android.InputMethodServices.Keyboard mKeyboard;
Activity activity;
global::Android.Views.View view;
protected override void OnElementChanged(ElementChangedEventArgs<Page> e)
{
base.OnElementChanged(e);
if (e.OldElement != null || Element == null)
{
return;
}
try
{
SetupUserInterface();
SetupEventHandlers();
this.AddView(view);
}
catch (System.Exception ex)
{
System.Diagnostics.Debug.WriteLine(#" ERROR: ", ex.Message);
}
}
void SetupUserInterface()
{
activity = this.Context as Activity;
view = activity.LayoutInflater.Inflate(Resource.Layout.activity_keyboard, this, false);
mKeyboard = new Android.InputMethodServices.Keyboard(Context, Resource.Xml.keyboard);
mTargetView = view.FindViewById<EditText>(Resource.Id.target);
mKeyboardView = view.FindViewById<CustomKeyboardView>(Resource.Id.keyboard_view);
mKeyboardView.Keyboard = mKeyboard;
}
void SetupEventHandlers()
{
mTargetView.Touch += (sender, e) =>
{
ShowKeyboardWithAnimation();
e.Handled = false;
mTargetView.ShowSoftInputOnFocus = false;
};
mKeyboardView.Key += async (sender, e) =>
{
long eventTime = JavaSystem.CurrentTimeMillis();
KeyEvent ev = new KeyEvent(eventTime, eventTime, KeyEventActions.Down, e.PrimaryCode, 0, 0, 0, 0, KeyEventFlags.SoftKeyboard | KeyEventFlags.KeepTouchMode);
DispatchKeyEvent(ev);
await Task.Delay(1);
mTargetView.RequestFocus();
};
}
public void ShowKeyboardWithAnimation()
{
if (mKeyboardView.Visibility == ViewStates.Gone)
{
mKeyboardView.Visibility = ViewStates.Visible;
Android.Views.Animations.Animation animation = AnimationUtils.LoadAnimation(
Context,
Resource.Animation.slide_in_bottom
);
mKeyboardView.ShowWithAnimation(animation);
}
}
protected override void OnLayout(bool changed, int l, int t, int r, int b)
{
base.OnLayout(changed, l, t, r, b);
var msw = MeasureSpec.MakeMeasureSpec(r - l, MeasureSpecMode.Exactly);
var msh = MeasureSpec.MakeMeasureSpec(b - t, MeasureSpecMode.Exactly);
view.Measure(msw, msh);
view.Layout(0, 0, r - l, b - t);
}
}
Effect:
.
I wrote up a simple demo about how to implement this feature, you can see it in this GitHub Repository.
I don't know Hebrew, if you need to achieve the effect like the picture you have post, you need custom the layout in keyboard.xml file.
Update :
I am done iOS portion using entry render so only try to do for android portion
I write a EntryRenderer to implement this feature, effect like this, hope this can help you.
public class MyEntry2Renderer : ViewRenderer<MyEntry, TextInputLayout>,
ITextWatcher,
TextView.IOnEditorActionListener
{
private bool _hasFocus;
public CustomKeyboardView mKeyboardView;
public Android.InputMethodServices.Keyboard mKeyboard;
ViewGroup activityRootView;
protected EditText EditText => Control.EditText;
public bool OnEditorAction(TextView v, ImeAction actionId, KeyEvent e)
{
if ((actionId == ImeAction.Done) || ((actionId == ImeAction.ImeNull) && (e.KeyCode == Keycode.Enter)))
{
Control.ClearFocus();
//HideKeyboard();
((IEntryController)Element).SendCompleted();
}
return true;
}
public virtual void AfterTextChanged(IEditable s)
{
}
public virtual void BeforeTextChanged(ICharSequence s, int start, int count, int after)
{
}
public virtual void OnTextChanged(ICharSequence s, int start, int before, int count)
{
if (string.IsNullOrWhiteSpace(Element.Text) && (s.Length() == 0)) return;
((IElementController)Element).SetValueFromRenderer(Entry.TextProperty, s.ToString());
}
protected override TextInputLayout CreateNativeControl()
{
var textInputLayout = new TextInputLayout(Context);
var editText = new EditText(Context);
#region Add the custom Keyboard in your Page
var activity = Forms.Context as Activity;
var rootView = activity.Window.DecorView.FindViewById(Android.Resource.Id.Content);
activity.Window.SetSoftInputMode(SoftInput.StateAlwaysHidden);
activityRootView = ((ViewGroup)rootView).GetChildAt(0) as ViewGroup;
mKeyboardView = new CustomKeyboardView(Forms.Context, null);
Android.Widget.RelativeLayout.LayoutParams layoutParams =
new Android.Widget.RelativeLayout.LayoutParams(LayoutParams.MatchParent, LayoutParams.WrapContent); // or wrap_content
layoutParams.AddRule(LayoutRules.AlignParentBottom);
activityRootView.AddView(mKeyboardView, layoutParams);
#endregion
//First open the current page, hide the Keyboard
mKeyboardView.Visibility = ViewStates.Gone;
//Use the custom Keyboard
mKeyboard = new Android.InputMethodServices.Keyboard(Context, Resource.Xml.keyboard2);
mKeyboardView.Keyboard = mKeyboard;
mKeyboardView.Key += async (sender, e) =>
{
long eventTime = JavaSystem.CurrentTimeMillis();
KeyEvent ev = new KeyEvent(eventTime, eventTime, KeyEventActions.Down, e.PrimaryCode, 0, 0, 0, 0, KeyEventFlags.SoftKeyboard | KeyEventFlags.KeepTouchMode);
DispatchKeyEvent(ev);
await Task.Delay(1);
};
textInputLayout.AddView(editText);
return textInputLayout;
}
protected override void OnElementChanged(ElementChangedEventArgs<MyEntry> e)
{
base.OnElementChanged(e);
if (e.OldElement != null)
if (Control != null)
EditText.FocusChange -= ControlOnFocusChange;
if (e.NewElement != null)
{
var ctrl = CreateNativeControl();
SetNativeControl(ctrl);
EditText.ShowSoftInputOnFocus = false;
EditText.FocusChange += ControlOnFocusChange;
}
}
private void ControlOnFocusChange(object sender, FocusChangeEventArgs args)
{
_hasFocus = args.HasFocus;
if (_hasFocus)
{
EditText.Post(() =>
{
EditText.RequestFocus();
ShowKeyboardWithAnimation();
});
}
else
{
//Hide the Keyboard
mKeyboardView.Visibility = ViewStates.Gone;
}
}
public void ShowKeyboardWithAnimation()
{
if (mKeyboardView.Visibility == ViewStates.Gone)
{
mKeyboardView.Visibility = ViewStates.Visible;
Android.Views.Animations.Animation animation = AnimationUtils.LoadAnimation(
Context,
Resource.Animation.slide_in_bottom
);
mKeyboardView.ShowWithAnimation(animation);
}
}
}

No 'output' extra specified Exception

I use the Google Photo app to pick gallery photo and then when I crop the picture and save, it catches an exception, Here is my code :
goto_picture.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
intent = new Intent(Intent.ACTION_PICK, null);
intent.setDataAndType(
MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
IMAGE_UNSPECIFIED);
startActivityForResult(intent, PHOTO_ZOOM);
dialog.cancel();
}
});
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (resultCode == Activity.RESULT_OK) {
if (requestCode == PHOTO_GRAPH) {
startPhotoZoom(Uri.fromFile(file));
String imagePath = SystemUtils.getSDPath() + "/temp.jpg";
File picture = new File(imagePath);
if (picture.exists()) {
pictureBitmap = BitmapFactory.decodeFile(imagePath);
ImageUtils.SaveCacheBitmap(pictureBitmap);
rvEditAvatar.setImageBitmap(pictureBitmap);
}
}
if (requestCode == PHOTO_ZOOM) {
startPhotoZoom(data.getData());
}
if (requestCode == PHOTO_RESULT) {
Bundle extras = data.getExtras();
if (extras != null) {
pictureBitmap = extras.getParcelable("data");
ByteArrayOutputStream stream = new ByteArrayOutputStream();
pictureBitmap.compress(Bitmap.CompressFormat.JPEG, 100,
stream);
ImageUtils.SaveCacheBitmap(pictureBitmap);
rvEditAvatar.setImageBitmap(pictureBitmap);
}
}
}
}
public void startPhotoZoom(Uri uri) {
Intent intent = new Intent("com.android.camera.action.CROP");
intent.setDataAndType(uri, "image/*");
intent.putExtra("crop", "true");
intent.putExtra("aspectX", 1);
intent.putExtra("aspectY", 1);
intent.putExtra("outputX", 180);
intent.putExtra("outputY", 180);
intent.putExtra("return-data", true);
intent.putExtra("outputFormat", Bitmap.CompressFormat.JPEG.toString());
startActivityForResult(intent, PHOTO_RESULT);
}
Logcat:
Process: com.google.android.apps.photos, PID: 7031
java.lang.RuntimeException: Unable to resume activity
{com.google.android.apps.photos/com.google.android.apps.photos.photoeditor.intents.EditActivity}:
java.lang.UnsupportedOperationException: No 'output' extra specified
and can not save to specified inputUri:
content://com.google.android.apps.photos.contentprovider/0/1/content%3A%2F%2Fmedia%2Fexternal%2Fimages%2Fmedia%2F72072/ACTUAL
As the exception said, you have to specify output extra like the following code.
intent.putExtra(MediaStore.EXTRA_OUTPUT, someOutPutPath);
And return data is not secure in case of big image cropped which may cause crash. I think that's why it forces you to use an output extra but not the data directly. So you may set the return-data to false as well:
intent.putExtra("return-data", false);
I meet this problem today, and solved by double check the data pass-back.I test following code on both Android L and Android 4. On Android L the fileUri is not empty while pre Android L we got fileUri null(in this case, I got the bitmap by simply getData).
private Bitmap decodeBitmapFromCrop(Intent data) {
Bundle extras = data.getExtras();
Bitmap photo = null;
if (extras != null) {
photo = extras.getParcelable("data");
} else {
Uri fileUri = data.getData();
if (fileUri != null) {
try {
photo = MediaStore.Images.Media.getBitmap(getContentResolver(), fileUri);
} catch (IOException e) {
XXLog.d(TAG, "Media.getBitmap", e);
}
}
}
return photo;
}

Web API Return OAuth Token as XML

Using the default Visual Studio 2013 Web API project template with individual user accounts, and posting to the /token endpoint with an Accept header of application/xml, the server still returns the response in JSON:
{"access_token":"...","token_type":"bearer","expires_in":1209599}
Is there a way to get the token back as XML?
According to RFC6749 the response format should be JSON and Microsoft implemented it accordingly. I found out that JSON formatting is implemented in Microsoft.Owin.Security.OAuth.OAuthAuthorizationServerHandler internal class with no means of extension.
I also encountered the need to have token response in XML.
The best solution I came up with was to implement HttpModule converting JSON to XML when stated in Accept header.
public class OAuthTokenXmlResponseHttpModule : IHttpModule
{
private static readonly string FilterKey = typeof(OAuthTokenXmlResponseHttpModule).Name + typeof(MemoryStreamFilter).Name;
public void Init(HttpApplication application)
{
application.BeginRequest += ApplicationOnBeginRequest;
application.EndRequest += ApplicationOnEndRequest;
}
private static void ApplicationOnBeginRequest(object sender, EventArgs eventArgs)
{
var application = (HttpApplication)sender;
if (ShouldConvertToXml(application.Context.Request) == false) return;
var filter = new MemoryStreamFilter(application.Response.Filter);
application.Response.Filter = filter;
application.Context.Items[FilterKey] = filter;
}
private static bool ShouldConvertToXml(HttpRequest request)
{
var isTokenPath = string.Equals("/token", request.Path, StringComparison.InvariantCultureIgnoreCase);
var header = request.Headers["Accept"];
return isTokenPath && (header == "text/xml" || header == "application/xml");
}
private static void ApplicationOnEndRequest(object sender, EventArgs eventArgs)
{
var context = ((HttpApplication) sender).Context;
var filter = context.Items[FilterKey] as MemoryStreamFilter;
if (filter == null) return;
var jsonResponse = filter.ToString();
var xDocument = JsonConvert.DeserializeXNode(jsonResponse, "oauth");
var xmlResponse = xDocument.ToString(SaveOptions.DisableFormatting);
WriteResponse(context.Response, xmlResponse);
}
private static void WriteResponse(HttpResponse response, string xmlResponse)
{
response.Clear();
response.ContentType = "application/xml;charset=UTF-8";
response.Write(xmlResponse);
}
public void Dispose()
{
}
}
public class MemoryStreamFilter : Stream
{
private readonly Stream _stream;
private readonly MemoryStream _memoryStream = new MemoryStream();
public MemoryStreamFilter(Stream stream)
{
_stream = stream;
}
public override void Flush()
{
_stream.Flush();
}
public override int Read(byte[] buffer, int offset, int count)
{
return _stream.Read(buffer, offset, count);
}
public override void Write(byte[] buffer, int offset, int count)
{
_memoryStream.Write(buffer, offset, count);
_stream.Write(buffer, offset, count);
}
public override string ToString()
{
return Encoding.UTF8.GetString(_memoryStream.ToArray());
}
#region Rest of the overrides
public override bool CanRead
{
get { throw new NotImplementedException(); }
}
public override bool CanSeek
{
get { throw new NotImplementedException(); }
}
public override bool CanWrite
{
get { throw new NotImplementedException(); }
}
public override long Seek(long offset, SeekOrigin origin)
{
throw new NotImplementedException();
}
public override void SetLength(long value)
{
throw new NotImplementedException();
}
public override long Length
{
get { throw new NotImplementedException(); }
}
public override long Position
{
get
{
throw new NotImplementedException();
}
set
{
throw new NotImplementedException();
}
}
#endregion
}
Ok I had such a fun time trying to figure this out using OWIN I thought I would share my solution with the community, I borrowed some insight from other posts https://stackoverflow.com/a/26216511/1148288 and https://stackoverflow.com/a/29105880/1148288 along with the concepts Alexei describs in his post. Nothing fancy doing with implementation but I had a requirement for my STS to return an XML formatted response, I wanted to keep with the paradigm of honoring the Accept header, so my end point would examine that to determine if it needed to run the XML swap or not. This is what I am current using:
private void ConfigureXMLResponseSwap(IAppBuilder app)
{
app.Use(async (context, next) =>
{
if (context.Request != null &&
context.Request.Headers != null &&
context.Request.Headers.ContainsKey("Accept") &&
context.Request.Headers.Get("Accept").Contains("xml"))
{
//Set a reference to the original body stream
using (var stream = context.Response.Body)
{
//New up and set the response body as a memory stream which implements the ability to read and set length
using (var buffer = new MemoryStream())
{
context.Response.Body = buffer;
//Allow other middlewares to process
await next.Invoke();
//On the way out, reset the buffer and read the response body into a string
buffer.Seek(0, SeekOrigin.Begin);
using (var reader = new StreamReader(buffer))
{
string responsebody = await reader.ReadToEndAsync();
//Using our responsebody string, parse out the XML and add a declaration
var xmlVersion = JsonConvert.DeserializeXNode(responsebody, "oauth");
xmlVersion.Declaration = new XDeclaration("1.0", "UTF-8", "yes");
//Convert the XML to a byte array
var bytes = Encoding.UTF8.GetBytes(xmlVersion.Declaration + xmlVersion.ToString());
//Clear the buffer bits and write out our new byte array
buffer.SetLength(0);
buffer.Write(bytes, 0, bytes.Length);
buffer.Seek(0, SeekOrigin.Begin);
//Set the content length to the new buffer length and the type to an xml type
context.Response.ContentLength = buffer.Length;
context.Response.ContentType = "application/xml;charset=UTF-8";
//Copy our memory stream buffer to the output stream for the client application
await buffer.CopyToAsync(stream);
}
}
}
}
else
await next.Invoke();
});
}
Of course you would then wire this up during startup config like so:
public void Configuration(IAppBuilder app)
{
HttpConfiguration httpConfig = new HttpConfiguration();
//Highly recommend this is first...
ConfigureXMLResponseSwap(app);
...more config stuff...
}
Hope that helps any other lost souls that find there way to the this post seeking to do something like this!
take a look here i hope it can help how to set a Web API REST service to always return XML not JSON
Could you retry by doing the following steps:
In the WebApiConfig.Register(), specify
config.Formatters.XmlFormatter.UseXmlSerializer = true;
var supportedMediaTypes = config.Formatters.XmlFormatter.SupportedMediaTypes;
if (supportedMediaTypes.Any(it => it.MediaType.IndexOf("application/xml", StringComparison.InvariantCultureIgnoreCase) >= 0) ==false)
{
supportedMediaTypes.Insert(0,new MediaTypeHeaderValue("application/xml"));
}
I normally just remove the XmlFormatter altogether.
// Remove the XML formatter
config.Formatters.Remove(config.Formatters.XmlFormatter);
Add the line above in your WebApiConfig class...
public static class WebApiConfig
{
public static void Register(HttpConfiguration config)
{
// Web API configuration and services
// Configure Web API to use only bearer token authentication.
config.SuppressDefaultHostAuthentication();
config.Filters.Add(new HostAuthenticationFilter(OAuthDefaults.AuthenticationType));
// Web API routes
config.MapHttpAttributeRoutes();
// Remove the XML formatter
config.Formatters.Remove(config.Formatters.XmlFormatter);
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
}
}

Resources