latest posts

Working on the Android port of jcBENCH today and ran into a question:
How to accurately detect the number of CPUs on a particular Android Device running at least Android version 4.0?

This led me to search around, I found a pretty intuitive native Java call:
Runtime.GetRuntime().AvailableProcessors(); ]]>
But this was returning 1 on my dual core Android devices. So I continued searching, one such suggestion on Stack Overflow was to count the number of files listed in the /sys/devices/system/cpu folder that began with cpu followed by a number. I ported the Java code listed in the Stack Overflow answer into C# and ran it on all 4 Android devices I own - all of them returned 3 (and looking at the actual listing only actually found a CPU0).

This got me thinking, I wonder if the traditional C# approach would work in this case? Xamarin afterall is built off of Mono....

Sure enough:
System.Environment.ProcessorCount ]]>
Returned properly on each device. Hopefully that helps someone out there.
Jumping back into MonoDroid development the last couple days at work after having not touched it in almost a year, I knew I was going to be rusty. Interestingly enough I'm finding it much closer to Windows Phone development than I remembered. Having had no luck in finding MonoDroid for Windows Phone Developers I figured I'd start an ongoing post.

Open a Browser

In Windows Phone you would open a Web Browser with the following function:
private void openBrowser(string url) {
     var task = new WebBrowserTask(); task.Uri = new Uri(url); task.Show(); }
]]>
However in MonoDroid you have to do this:
private void openBrowser(string url) {
     var browserIntent = new Intent(Intent.ActionView, Android.Net.Uri.Parse(url)); StartActivity(browserIntent); }
]]>

New Line in TextView

In Windows Phone in your XAML you'd do something like this to insert a new line into your TextBlock:
<TextBlock>This line is awesome<LineBreak/>but this one is better</TextBlock> ]]>
However in MonoDroid you need to be sure to set the singleLine property to false like so:
<TextView android:layout_width="fill_parent" android:singleLine="false" android:text="This line is awesome\r\nbut this one is better" /> ]]>

Login form (aka tapping enter goes to next field, with the last field hiding the keyboard)

In your XAML on Windows Phone you might have something like the following:
<StackPanel Orientation="Vertical"> <TextBox x:Name="TextBoxUsername" /> <TextBox x:Name="TextBoxPassword" /> </StackPanel> ]]>
And then in your code behind:
public LoginPage() {
     InitializeComponent(); TextBoxUsername.KeyDown += TextBoxUsername_KeyDown; TextBoxPassword.KeyDown += TextBoxPassword_KeyDown; }
void TextBoxUsername_KeyDown(object sender, KeyEventArgs e) {
     if (e.Key == Key.Enter) {
     TextBoxPassword.Focus(); }
}
void TextBoxPassword_KeyDown(object sender, KeyEventArgs e) {
     if (e.Key == Key.Enter) {
     Focus(); }
}
]]>
Basically upon hitting the enter key while in the TextBoxUsername field it will set the focus to the TextBoxPassword field. Upon hitting enter in the TextBoxPassword field, it will set the focus to the main page and close the keyboard. For MonoDroid, it is a little different. In your axml:
<EditText android:id="@+id/TextBoxUsername" android:imeOptions="actionNext" android:singleLine="true" android:layout_width="fill_parent" android:layout_height="wrap_content" /> <EditText android:id="@+id/TextBoxPassword" android:imeOptions="actionDone" android:singleLine="true" android:layout_width="fill_parent" android:layout_height="wrap_content" /> ]]>
The key part is the android:imeOptions values, actionNext will move the focus to the next EditText field and the actionDone will send the done command back to your keylisteners etc. In your Activity code behind, you need to add this override. Update the Resource.Id.xxxxxxx with the name of the field you want the keyboard to hide upon hitting enter:
public override bool DispatchKeyEvent(KeyEvent e) {
     if (CurrentFocus.Id == Resource.Id.TextBoxPasswordKey && (e.KeyCode == Keycode.NumpadEnter || e.KeyCode == Keycode.Enter)) {
     var imm = GetSystemService(Context.InputMethodService) as InputMethodManager; if (imm != null) {
     imm.HideSoftInputFromWindow(this.CurrentFocus.WindowToken, 0); }
return true; }
return base.DispatchKeyEvent(e); }
]]>
I should also note you'll need the using Android.Views.InputMethods; line added to your code behind as well.

Capturing Images via the Camera

In Windows Phone capturing images from your Library or Taking a new picture is pretty trivial, assuming you have a Button to choose/take the picture:
PhotoChooserTask _pcTask = null; private byte[] _pictureBytes; public PictureUpload() {
     InitializeComponent(); _pcTask = new PhotoChooserTask(); _pcTask.Completed += new EventHandler<PhotoResult>(_pcTask_Completed); }
void _pcTask_Completed(object sender, PhotoResult e) {
     if (e.TaskResult == TaskResult.OK) {
     MemoryStream ms = new MemoryStream(); e.ChosenPhoto.CopyTo(ms); _pictureBytes = ms.ToArray(); ms.Dispose(); }
}
private void btnChooseImage_Click(object sender, RoutedEventArgs e) {
     _pcTask.ShowCamera = true; _pcTask.Show(); }
]]>
From there just upload the _pictureBytes to your WCF Service or wherever. In MonoDroid as expected is a little different, assuming you have a button click event to take the picture and an ImageView to display the image:
private string _imageUri; // Global variable to access the image's Uri later void btnChooseImage_Click(object sender, EventArgs e) {
     var uri = ContentResolver.Insert(isMounted ? Android.Provider.MediaStore.Images.Media.ExternalContentUri : Android.Provider.MediaStore.Images.Media.InternalContentUri, new ContentValues()); _imageUri = uri.ToString(); var i = new Intent(Android.Provider.MediaStore.ActionImageCapture); i.PutExtra(Android.Provider.MediaStore.ExtraOutput, uri); StartActivityForResult(i, 0); }
protected override void OnActivityResult(int requestCode, Result resultCode, Intent data) {
     if (resultCode == Result.Ok && requestCode == 0) {
     imageView = FindViewById<ImageView>(Resource.Id.ivThumbnail); imageView.DrawingCacheEnabled = true; imageView.SetImageURI(Android.Net.Uri.Parse(_imageUri)); }
}
]]>
At this point you have the picture taken and the Uri of the image. In your Layout:
<Button android:text="Choose Image" android:id="@+id/btnChooseImage" android:layout_width="fill_parent" android:layout_height="wrap_content" /> <ImageView android:id="@+id/ivThumbnail" android:layout_width="300dp" android:layout_height="150dp" /> ]]>

Loading a picture from local storage and avoiding the dreaded java.lang.outofmemory exception

A fairly common scenario, maybe pulling an image from the code described above, now you want to upload it some where? In the Windows Phone above in addition to taking/capturing the picture, we have a byte[] with the data, on MonoDroid it is a little different. A situation I ran into on my HTC Vivid was a java.lang.outofmemory exception. Further investigation, apparently Android has a 24mb VM limit per app (and some devices it is set to 16mb). Doing some research, I came across Twig's post. As expected it was in Java, so I converted it over to MonoDroid and added some additional features to fit my needs. So literally this function will return a scaled Bitmap object for you to turn around and convert to a Byte[]. The function:
private Android.Graphics.Bitmap loadBitmapFromURI(Android.Net.Uri uri, int maxDimension) {
     var inputStream = ContentResolver.OpenInputStream(uri); var bfOptions = new Android.Graphics.BitmapFactory.Options(); bfOptions.InJustDecodeBounds = true; var bitmap = Android.Graphics.BitmapFactory.DecodeStream(inputStream, null, bfOptions); inputStream.Close(); var resizeScale = 1; if (bfOptions.OutHeight > maxDimension || bfOptions.OutWidth > maxDimension) {
     resizeScale = (int)Math.Pow(2, (int)Math.Round(Math.Log(maxDimension / (double)Math.Max(bfOptions.OutHeight, bfOptions.OutWidth)) / Math.Log(0.5))); }
bfOptions = new Android.Graphics.BitmapFactory.Options(); bfOptions.InSampleSize = resizeScale; inputStream = ContentResolver.OpenInputStream(uri); bitmap = Android.Graphics.BitmapFactory.DecodeStream(inputStream, null, bfOptions); inputStream.Close(); return bitmap; }
]]>
For a practical use, loading the image, scaling if necessary and then getting a Byte[]:
var bitmap = loadBitmapFromURI(Android.Net.Uri.Parse(_imageUri), 800); var ms = new MemoryStream(); bitmap.Compress(Android.Graphics.Bitmap.CompressFormat.Jpeg, 100, ms); ]]>
At this point doing a ms.ToArray() will get you to the same point the Windows Phone code above did, so if you had a WCF Service, you could at this point upload the byte array just as you could with a Windows Phone above.

Transparent Background on a ListView, LayoutView etc?

In Windows Phone you can set the Background or Foreground properties to simply Transparent like so:
<StackPanel Background="Transparent" Orientation="Vertical"> <TextBlock>Transparentcy is awesome</TextBlock> </StackPanel> ]]>
In MonoDroid it's simply "@null" like so for the ListView
<ListView android:background="@null" android:layout_width="match_parent" android:layout_height="match_parent"> <TextView android:text="Transparentcy is awesome" android:gravity="center" /> ]]>

Locking Orientation

In Windows Phone you can set your page's orientation to be forced into Landscape or Portrait in your xaml like so:
<phone:PhoneApplicationPage SupportedOrientations="Portrait" Orientation="Portrait"> ]]>
In MonoDroid I couldn't figure out a better way to do it than the following line inside your Activity's OnCreate function like so:
protected override void OnCreate(Bundle bundle) {
     base.OnCreate(bundle); RequestedOrientation = ScreenOrientation.Portrait; }
]]>
On a side note, you'll need to add this line to the top of your Activity if it isn't already there: using Android.Content.PM;