Showing posts with label MonoDroid. Show all posts
Showing posts with label MonoDroid. Show all posts

Sunday, June 16, 2013

Example of Deleting from SQLite DB using C# in Xamarin Android

I tried to use LINQ syntax to delete my objects from a table like shown here, but got an error "Cannot store type:  MyObject":

private static void DeleteOldObjects()
{
 string path = Path.Combine (System.Environment.GetFolderPath (System.Environment.SpecialFolder.MyDocuments), "MyDatabase.db");
 var db = new SQLiteConnection(path,password,false);
 var query = db.Table<MyObject>().Where(rt => rt.Date < DateTime.Now.AddDays(-3));

 if (query != null) {
  foreach (var object in query.ToList<MyObject>()) {
   db.Delete<MyObject>(object);
  }
 }
 db.Commit ();
}

From what I could determine by looking at the SQLite.cs code, it seems like this error is when it's trying to bind my object as a parameter:


internal static void BindParameter (IntPtr stmt, int index, object value)
{
  if (value == null) {
    SQLite3.BindNull (stmt, index);
  } else {
    if (value is Int32) {
      SQLite3.BindInt (stmt, index, (int)value);
    } else if (value is String) {
      SQLite3.BindText (stmt, index, (string)value, -1, NegativePointer);
    } else if (value is Byte || value is UInt16 || value is SByte || value is Int16) {
      SQLite3.BindInt (stmt, index, Convert.ToInt32 (value));
    } else if (value is Boolean) {
      SQLite3.BindInt (stmt, index, (bool)value ? 1 : 0);
    } else if (value is UInt32 || value is Int64) {
      SQLite3.BindInt64 (stmt, index, Convert.ToInt64 (value));
    } else if (value is Single || value is Double || value is Decimal) {
      SQLite3.BindDouble (stmt, index, Convert.ToDouble (value));
    } else if (value is DateTime) {
      SQLite3.BindText (stmt, index, ((DateTime)value).ToString ("yyyy-MM-dd HH:mm:ss"), -1, NegativePointer);
    } else if (value.GetType ().IsEnum) {
      SQLite3.BindInt (stmt, index, Convert.ToInt32 (value));
    } else if (value is byte[]) {
      SQLite3.BindBlob (stmt, index, (byte[])value, ((byte[])value).Length, NegativePointer);
    } else {
      throw new NotSupportedException ("Cannot store type: " + value.GetType ());
    }
  }
}

That seemed to me like the most intuitive way to perform that task since it's the same syntax used to insert objects, but since it didn't work I found you actually need to pass the primary key of the object you want to delete, like this:

private static void DeleteOldObjects()
{
 string path = Path.Combine (System.Environment.GetFolderPath (System.Environment.SpecialFolder.MyDocuments), "MyDatabase.db");
 var db = new SQLiteConnection(path,password,false);
 DateTime expireDate = DateTime.Now.AddDays(-3));
 var query = db.Table<MyObject>().Where(rt => rt.Date < expireDate );

 if (query != null) {
  foreach (var object in query.ToList<MyObject>()) {
   db.Delete<MyObject>(object.PrimaryKeyId);
  }
 }
 db.Commit ();
}

Tuesday, May 14, 2013

Defining ContextMenus for ListView Items in Xamarin Android

While working on my Android app I had need to display a list of items with position-dependent context menus.  It took me awhile to develop a clean solution so I'd like to share my work with anyone who would like dynamic menus available on their ListViews that display over items using a long-press.

Inside of my Activity class I have declared three important variables:

private ListView itemList;
private int selectedItemNumber;
private string selectedItemText;

What each variable tracks should be self explanatory from the declaration, but please comment if you have questions on anything in my posts.  The reason it's important to declare these within scope of the Activity class and not within a method is because we lose focus of what ListView item is being interacted with in-between the step of creating a menu and when that menu is used.  There might be a way to extract that information from the second step, but none was obvious to me and I found the approach of using private variables an easy solution.

In addition to those three variables I've also created constant values to track the int-based menu options:

private const int EDIT_ITEM = 0;
private const int VIEW_ITEM = 1;
private const int DELETE_ITEM = 2;

These allow me to refer to actions in a clear way in the code.  In the OnCreate method of my Activity there are two important steps needed to use context menus:

protected override void OnCreate (Bundle bundle)
{
 base.OnCreate (bundle);
 SetContentView (Resource.Layout.SendTickets);

 //Two important steps to for my context menus
 itemList = (ListView) FindViewById(Resource.Id.myListViewName);
 RegisterForContextMenu(itemList);

}

Now that I've associated my ListView with a private variable and have registered it for ContextMenus I only have to define two additional methods for everything to work.  The first is the method that is triggered when an item is selected because of the RegisterForContextMenu call made in OnCreate, and it creates the menu that is displayed:

public override void OnCreateContextMenu(IContextMenu menu, View v, IContextMenuContextMenuInfo info)
{
 AdapterViewAdapterContextMenuInfo menuInfo = (AdapterView.AdapterContextMenuInfo) info;
 
 selectedItemText = ((TextView) menuInfo.TargetView).Text;
 selectedItemId = menuInfo.Id;

 //My listview is set to have a "No Data" item on the first row if it's empty
 if (!selectedTicketText.Equals("No Data"))
 {
  menu.SetHeaderTitle("My Menu Header");
  //All items can be viewed
  menu.Add(0, VIEW_ITEM, 0, "View Item");
  //But only the first item in the list can be edited
  if (selectedItemId== 0)
   menu.Add(0, EDIT_ITEM, 0, "Edit Item");

  if (!selectedTicketText.Contains ("Words that mean it can be deleted"))
   menu.Add (0, DELETE_ITEM, 0, "Delete Item");
 }
 else  //This won't create any menu at all
 {
  menu.SetHeaderTitle("No Options");
 }
}

Okay, so now my menu will show up and it will look different based on what text the item in the ListView contains, and what item number it is assigned, which is the 0-based index in the listview.  You can see in my menu code above that I have added the ability to View to any-and-all items, but only the first item in the list can be edited, and only items containing my special text can be deleted.

The last step is to specify what actions occur when the menu is used.  We do this in the OnContextItemSelected method:

public override bool OnContextItemSelected(IMenuItem item)
{
 if (item.ItemId.Equals (VIEW_ITEM)) 
 {
  MethodThatViewsMyItem(selectedItemText);
 } 
 else if (item.ItemId.Equals(EDIT_ITEM))
 {
  MethodThatEditsMyItem(selectedItemNumber);
 }
 else if (item.ItemId.Equals(DELETE_ITEM))
 {
  MethodThatDeletesMyItem(selectedItemNumber);
 }

 return base.OnOptionsItemSelected(item);
}

This is where the information captured as selectedItemText and selectedItemNumber from OnCreateContextMenu comes in handy.  Since this method only has access to the item that was clicked, and that IMenuItem contains no information about the ListView item we have to refer to our Activity-scope variables selectedItemText and selectedItemNumber.

As always, feel free to post questions or comments, even if it's to suggest a better way of doing this!

Tuesday, April 23, 2013

Creating Custom Overlays in Xzing Barcode Scanner using Xamarin Studio and C#



I've recently had need to customize the UI overlay of the excellent and free barcode scanning plugin Zxing.   While gathering material for this post I discovered that an example is provided of customizing the overlay via XML, but when I initially searched the first example I came across was the C# method - so that's the route I took.  The C# version did not have the ability to turn the flash on/off which was a feature I needed to access, so I figured out how to add that while styling.  I'm going to go over how I modified the example class created by Redth to help anyone else who might attempt the same thing for their own Android app.

For starters, you need to modify your call to Zxing to specify the use of a custom overlay:

var scanner = new ZXing.MobileMobileBarcodeScanner();
scanner.UseCustomOverlay = true;
myCustomOverlayInstance = new ZxingOverlayView(this, scanner);
scanner.CustomOverlay = myCustomOverlayInstance;
scanner.Scan().ContinueWith(t => { //Handle Result });

After that, you just need to customize the properties and methods of the ZxingOverlayView example class file.  In my example I added the ability to control the torch (flashlight) and display bitamaps so that I could have my own custom buttons.  I specified a default color and a pressed color, along with boolean flags so I could change the buttons to confirm to the user that they had pressed a button while waiting for a response:

namespace MyProject
{
 public class ZxingOverlayView : View 
 {
  private Paint defaultPaint;
  private Paint pressedPaint;
  private Android.Graphics.Bitmap resultBitmap;
  private Android.Graphics.Bitmap litTorchIcon;
                private Android.Graphics.Bitmap unlitTorchIcon;
  private Rect torchIconDimRect;
  private bool hasTorch = false;
  private bool torchOn = false;
  private bool cancelPressed = false;
  private bool problemPressed = false;
...
public ZxingOverlayView(Context context, MobileBarcodeScanner scanner) : base(context)
{
 this.context = context;
 this.scanner = scanner;
 
 SetDisplayValues ();
}
...
private void SetDisplayValues ()
{
 //Determine if device has flash/torch
 hasTorch = this.Context.PackageManager.HasSystemFeature (PackageManager.FeatureCameraFlash);
 if (hasTorch) {
  //Load button icons
  var metrics = Resources.DisplayMetrics;
  int iconHeight = metrics.HeightPixels * 2 / 9;
  int iconWidth = iconHeight * 7 / 10;
  torchIconDimRect = new Rect (0, 0, iconWidth, iconHeight);
  litTorchIcon = ImageHelper.DecodeSampledBitmapFromResource (Resources, Resource.Drawable.bulb_lit, iconWidth, iconHeight);
  unlitTorchIcon = ImageHelper.DecodeSampledBitmapFromResource (Resources, Resource.Drawable.bulb_unlit, iconWidth, iconHeight);
 }
 // Initialize these once for performance rather than calling them every time in onDraw()
 defaultPaint = new Paint (PaintFlags.AntiAlias);
 pressedPaint = new Paint (PaintFlags.AntiAlias);
 pressedPaint.Color = new Color (96, 97, 104);
 buttonFontColor = Color.White;

For each of my buttons I had to specify a rectangle on the screen.  It's best if you specify not in static pixels, but in percentage of the total screen available.  This will ensure your overlay renders the same on any size of screen.  I created three buttons, plus a rectangle to hold my torch icon bitmap.  Notice that the TorchIconDimRect was created as part of SetDisplayValues() above as we decoded and resized the bitmap icon for it at the same time:

Rect GetProblemButtonRect()
{
 
 var metrics = Resources.DisplayMetrics;
 int width = metrics.WidthPixels * 7 / 16 ;
 int height = metrics.HeightPixels * 2 / 9;
 int leftOffset = metrics.WidthPixels * 33 / 64;
 int topOffset = metrics.HeightPixels * 3 / 4;
 var problemRect = new Rect(leftOffset, topOffset, leftOffset + width, topOffset + height);
 
 return problemRect;
}

Rect GetCancelButtonRect()
{
 var metrics = Resources.DisplayMetrics;
 int width = metrics.WidthPixels * 7 / 16 ;
 int height = metrics.HeightPixels * 2 / 9;
 int leftOffset = metrics.WidthPixels / 22;
 int topOffset = metrics.HeightPixels * 3 / 4;
 var cancelRect = new Rect(leftOffset, topOffset, leftOffset + width, topOffset + height);
 
 return cancelRect;
}

Rect GetTorchIconDimRect()
{
 return torchIconDimRect;
}

Rect GetTorchIconRect()
{
 var metrics = Resources.DisplayMetrics;
 int height = metrics.HeightPixels / 8;
 int width = height * 7 / 10;
 int leftOffset = metrics.WidthPixels / 2 - ( width / 2);
 int topOffset = metrics.HeightPixels /18;
 var torchRect = new Rect(leftOffset, topOffset, leftOffset + width, topOffset + height);
 
 return torchRect;
}

Rect GetTorchButtonRect()
{
 var metrics = Resources.DisplayMetrics;
 int width = metrics.WidthPixels * 3 / 8 ;
 int height = metrics.HeightPixels * 3 / 16;
 int leftOffset = metrics.WidthPixels / 2 - (width / 2);
 int topOffset = metrics.HeightPixels / 64;
 var torchRect = new Rect(leftOffset, topOffset, leftOffset + width, topOffset + height);
 
 return torchRect;
}

Here is the ImageHelper class file which you will only need if you are using bitmaps on your overlay.  This helper class will resize your bitmap to the desired height to prevent image distortion:

internal static class ImageHelper
{
 public static int CalculateInSampleSize(BitmapFactoryOptions options, int reqWidth, int reqHeight)
 {
  // Raw height and width of image
  var height = (float)options.OutHeight;
  var width = (float)options.OutWidth;
  var inSampleSize = 1D;
  
  if (height > reqHeight || width > reqWidth)
  {
   inSampleSize = width > height
    ? height/reqHeight
     : width/reqWidth;
  }
  
  return (int) inSampleSize;
 }
 
 public static Bitmap DecodeSampledBitmapFromResource(Resources res, int resId, int reqWidth, int reqHeight)
 {
  // First decode with inJustDecodeBounds=true to check dimensions
  var options = new BitmapFactoryOptions { InJustDecodeBounds = true };
  BitmapFactory.DecodeResource(res, resId, options); 
  
  // Calculate inSampleSize
  options.InSampleSize = CalculateInSampleSize(options, reqWidth, reqHeight);
  
  // Decode bitmap with inSampleSize set
  options.InJustDecodeBounds = false;
   Bitmap optimalSize = BitmapFactory.DecodeResource (res, resId, options);
   return Bitmap.CreateScaledBitmap (optimalSize, reqWidth, reqHeight, false);
 }
}

So now that all the colors, shapes and bitmaps have been defined you just need to draw them to the screen.  This is done through the OnDraw() method:

protected override void OnDraw (Canvas canvas)
{
 var scale = Resources.DisplayMetrics.Density;
 
 var frame = GetFramingRect();
 if (frame == null)
  return;
 
 var probBtn = GetProblemButtonRect();
 var cancelBtn = GetCancelButtonRect();
 var torchBtn = GetTorchButtonRect();
 
 var width = canvas.Width;
 var height = canvas.Height;
 var textPaint = new TextPaint();
 textPaint.Color = buttonFontColor;
 textPaint.AntiAlias = true;
 textPaint.BgColor = Color.Gray;
 textPaint.TextSize = 16 * scale;
 
 //Draw mask
 defaultPaint.Color = resultBitmap != null ? resultColor : maskColor;
 defaultPaint.Alpha = 245;
 canvas.DrawRect(0, 0, width, frame.Top, defaultPaint);
 canvas.DrawRect(0, frame.Bottom + 1, width, height, defaultPaint);
 
 //Draw button outlines
 defaultPaint.Color = buttonFontColor;
 defaultPaint.Alpha = 255;
 pressedPaint.Color = Color.Black;
 canvas.DrawRect (probBtn.Left+1, probBtn.Top +1, probBtn.Right + 1, probBtn.Bottom + 1, problemPressed ? pressedPaint : defaultPaint);
 canvas.DrawRect (cancelBtn.Left+1, cancelBtn.Top +1, cancelBtn.Right + 1, cancelBtn.Bottom + 1, cancelPressed ? pressedPaint : defaultPaint);
 if (hasTorch)
  canvas.DrawRect (torchBtn.Left + 1, torchBtn.Top + 1, torchBtn.Right + 1, torchBtn.Bottom + 1, torchOn ? pressedPaint : defaultPaint);
 
 //Draw buttons
 defaultPaint.Color = buttonColor;
 defaultPaint.Alpha = 255;
 pressedPaint.Color = new Color(96, 97, 104);
 canvas.DrawRect (probBtn, problemPressed ? pressedPaint : defaultPaint);
 canvas.DrawRect (cancelBtn, cancelPressed ? pressedPaint : defaultPaint);
 if (hasTorch)
 {
  canvas.DrawRect (torchBtn, torchOn ? pressedPaint : defaultPaint);
  //Draw button icons
  canvas.DrawBitmap ((torchOn ? litTorchIcon : unlitTorchIcon), GetTorchIconDimRect(), GetTorchIconRect(), defaultPaint);
 }
 
 //Draw button text
 var btnText = new StaticLayout("Scan problems?", textPaint, probBtn.Width(), Android.Text.Layout.Alignment.AlignCenter, 1.0f, 0.0f, false);
 canvas.Save();
 canvas.Translate(probBtn.Left, probBtn.Top + (probBtn.Height ()/3)+ (btnText.Height / 2));
 btnText.Draw(canvas);
 canvas.Restore();
 btnText = new StaticLayout("Cancel Scan", textPaint, cancelBtn.Width(), Android.Text.Layout.Alignment.AlignCenter, 1.0f, 0.0f, false);
 canvas.Save();
 canvas.Translate(cancelBtn.Left, cancelBtn.Top + (cancelBtn.Height ()/3) + (btnText.Height / 2));
 btnText.Draw(canvas);
 canvas.Restore();

If your buttons are pressed, you can capture that event by overriding the OnTouchEvent method.  Notice that in each button touch event I call this.Invalidate().  This call causes the screen to refresh and without it the OnDraw() method would not be invoked, and the screen would not reflect our buttons change in display when pressed.

public override bool OnTouchEvent(MotionEvent me)
{
 if (me.Action == MotionEventActions.Down)
 {
  if (GetCancelButtonRect().Contains((int)me.RawX, (int)me.RawY))
  {
   cancelPressed = true;
   this.Invalidate();
   OnUnload();
   scanner.Cancel();
  }
  else if (GetTorchButtonRect().Contains ((int)me.RawX, (int)me.RawY))
  {
   scanner.ToggleTorch();
   torchOn = !torchOn;
   this.Invalidate();
  }
  else if (GetProblemButtonRect().Contains ((int)me.RawX, (int)me.RawY))
  {
   problemPressed = true;
   this.Invalidate();
   
   if (parentActivity == null)
   {
    Intent intent = new Intent();
    intent.SetClass(context, typeof(ManualEntryActivity));
    context.StartActivity(intent);
   }
   else
   {
    parentActivity.GetManualEntry();
   }
   OnUnload();
   scanner.Cancel();
  }
  return true;
 }
 else
  return false;
}

Lastly, I read on a stackoverflow post that graphics and bitmaps are two objects which you must take care to properly dispose of when they are no longer needed  If you don't properly dispose of the bitmaps created for your custom overlay then there is a potential for a memory leak.  I dispose of my bitmaps by calling this OnUnload() method that I use at all points of exit:

private void OnUnload()
{
 if (hasTorch)
 {
  litTorchIcon.Dispose();
  unlitTorchIcon.Dispose();
 }
}

This is how my custom overlay turned out.  (Ignore the black & white checkerboard with green square which is just a test display for the android emulator's camera)


Hopefully my post helped you.  Feel free to post questions if you are having problems, or need an explanation on any of my code.

Wednesday, February 6, 2013

DialogFragment Mono for Android.

Wanted to make a Dialog fragment, for uploading a picture from either the photo gallery in Android or from the Camera.  I wanted to really start doing a lot of dialogfragments.  I like that I can use them as fragments in activities or make them float above as dialogs.. Gives me twice the functionality as just making a normal fragment.   Of course, it does require at least 2.2 on the API side.

The Code:

public class CameraDialogFragment : DialogFragment
    {
        ImageButton camera;
        ImageButton gallery;
        
        public override Android.Views.View OnCreateView(Android.Views.LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
        {

            Dialog.Window.RequestFeature(WindowFeatures.NoTitle);

            var view = inflater.Inflate(Resource.Layout.CameraDialog, container, true);

            gallery = view.FindViewById<ImageButton>(Resource.Id.imageButton2);
            gallery.Click += delegate {

            };

            camera = view.FindViewById<ImageButton>(Resource.Id.imageButton1);
            camera.Click += delegate {

            };
            
            return view;
        }
        
        public override void OnResume()
        {
        
            Dialog.Window.SetLayout(LinearLayout.LayoutParams.WrapContent, LinearLayout.LayoutParams.WrapContent);
            
        
            Dialog.Window.SetBackgroundDrawable(new ColorDrawable(Color.Transparent));
            
        
            SetStyle(DialogFragmentStyle.NoFrame, Resource.Style.YouthImpactTheme);
            
            base.OnResume();
        }
        

        
        protected override void Dispose(bool disposing)
        {
            base.Dispose(disposing);
            

        }
        
    }

The XML:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content">
    <ImageButton
        android:src="@drawable/Camera3"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:id="@+id/imageButton1" />
    <ImageButton
        android:src="@drawable/Gallery"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:id="@+id/imageButton2" />
</LinearLayout>


The result:




Tuesday, January 29, 2013

Cloud Print in MonoDroid or MonoTouch.

Printed from Google Cloud Print via Mono Droid.
I spent quite a bit of time.. trying to print in Mono for Android via Google Cloud Print, I needed it for a piece or three I've been working on.

Stack Overflow Google Cloud Print

This link, basically got me through everything, and here is the code, tweaked a bit to remove the Proxy issue.  If you need the Proxy code, you can go pull from the original post.

Update :

Git Hub Repo with Google Cloud Print for Monodroid.

[You should easily be able to modify this to work for MonoTouch also.  I submitted the project to Xamarin, and they said they would have the Documentation team add an example]

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net;
using Android.App;
using Android.Content;
using Android.OS;
using Android.Runtime;
using Android.Views;
using Android.Widget;
using System.Web;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Json;
using System.IO;
using System.ServiceModel.Web;

namespace GoogleCloudPrint
{
    public class GoogleCloudPrint
    {
        public string UserName { get; set; }
        public string Password { get; set; }
        public string Source { get; set; }
        
        private const int ServiceTimeout = 10000;
        

        
        public CloudPrintJob PrintDocument (string printerId, string title, byte[] document, String mimeType)
        {
            try
            {
                string authCode;
                if (!Authorize (out authCode))
                return new CloudPrintJob { success = false };
                
                var b64 = Convert.ToBase64String (document);
                
                var request = (HttpWebRequest)WebRequest.Create ("http://www.google.com/cloudprint/submit?output=json&printerid=" + printerId);
                request.Method = "POST";
                
                // Setup the web request
                request.ServicePoint.Expect100Continue = false;
                
                // Add the headers
                request.Headers.Add ("X-CloudPrint-Proxy", Source);
                request.Headers.Add ("Authorization", "GoogleLogin auth=" + authCode);
                
                var p = new PostData ();
                
                p.Params.Add (new PostDataParam { Name = "printerid", Value = printerId, Type = PostDataParamType.Field });
                p.Params.Add (new PostDataParam { Name = "capabilities", Value = "{\"capabilities\":[{}]}", Type = PostDataParamType.Field });
                p.Params.Add (new PostDataParam { Name = "contentType", Value = "dataUrl", Type = PostDataParamType.Field });
                p.Params.Add (new PostDataParam { Name = "title", Value = title, Type = PostDataParamType.Field });
                
                p.Params.Add (new PostDataParam
                              {
                    Name = "content",
                    Type = PostDataParamType.Field,
                    Value = "data:" + mimeType + ";base64," + b64
                });
                
                var postData = p.GetPostData ();

                
                byte[] data = Encoding.UTF8.GetBytes (postData);
                
                request.ContentType = "multipart/form-data; boundary=" + p.Boundary;
                
                Stream stream = request.GetRequestStream ();
                stream.Write (data, 0, data.Length);
                stream.Close ();
                
                // Get response
                var response = (HttpWebResponse)request.GetResponse ();
                var responseContent = new StreamReader (response.GetResponseStream ()).ReadToEnd ();
                
                var serializer = new DataContractJsonSerializer (typeof (CloudPrintJob));
                var ms = new MemoryStream (Encoding.Unicode.GetBytes (responseContent));
                var printJob = serializer.ReadObject (ms) as CloudPrintJob;
                
                return printJob;
            }
            catch (Exception ex)
            {
                return new CloudPrintJob { success = false, message = ex.Message };
            }
        }
        
        public CloudPrinters Printers
        {
            get
            {
                var printers = new CloudPrinters ();
                
                string authCode;
                if (!Authorize (out authCode))
                return new CloudPrinters { success = false };
                
                try
                {
                    var request = (HttpWebRequest)WebRequest.Create ("http://www.google.com/cloudprint/search?output=json");
                    request.Method = "POST";
                    
                    // Setup the web request
                    request.ServicePoint.Expect100Continue = false;
                    
                    // Add the headers
                    request.Headers.Add ("X-CloudPrint-Proxy", Source);
                    request.Headers.Add ("Authorization", "GoogleLogin auth=" + authCode);
                    
                    request.ContentType = "application/x-www-form-urlencoded";
                    request.ContentLength = 0;
                    
                    var response = (HttpWebResponse)request.GetResponse ();
                    var responseContent = new StreamReader (response.GetResponseStream ()).ReadToEnd ();
                    
                    var serializer = new DataContractJsonSerializer (typeof (CloudPrinters));
                    var ms = new MemoryStream (Encoding.Unicode.GetBytes (responseContent));
                    printers = serializer.ReadObject (ms) as CloudPrinters;
                    
                    return printers;
                }
                catch (Exception)
                {
                    return printers;
                }
            }
        }
        
        private bool Authorize (out string authCode)
        {
            var result = false;
            authCode = "";
            
            var queryString = String.Format ("https://www.google.com/accounts/ClientLogin?accountType=HOSTED_OR_GOOGLE&Email={0}&Passwd={1}&service=cloudprint&source={2}",
                                             UserName, Password, Source);
            var request = (HttpWebRequest)WebRequest.Create (queryString);
            
            request.ServicePoint.Expect100Continue = false;
            
            var response = (HttpWebResponse)request.GetResponse ();
            var responseContent = new StreamReader (response.GetResponseStream ()).ReadToEnd ();
            
            var split = responseContent.Split ('\n');
            foreach (var s in split)
            {
                var nvsplit = s.Split ('=');
                if (nvsplit.Length == 2)
                {
                    if (nvsplit[0] == "Auth")
                    {
                        authCode = nvsplit[1];
                        result = true;
                    }
                }
            }
            
            return result;
        }

    }

    [DataContract]
    public class CloudPrinter
    {
        [DataMember (Order = 0)]
        public string id { get; set; }
        
        [DataMember (Order = 1)]
        public string name { get; set; }
        
        [DataMember (Order = 2)]
        public string description { get; set; }
        
        [DataMember (Order = 3)]
        public string proxy { get; set; }
        
        [DataMember (Order = 4)]
        public string status { get; set; }
        
        [DataMember (Order = 5)]
        public string capsHash { get; set; }
        
        [DataMember (Order = 6)]
        public string createTime { get; set; }
        
        [DataMember (Order = 7)]
        public string updateTime { get; set; }
        
        [DataMember (Order = 8)]
        public string accessTime { get; set; }
        
        [DataMember (Order = 9)]
        public bool confirmed { get; set; }
        
        [DataMember (Order = 10)]
        public int numberOfDocuments { get; set; }
        
        [DataMember (Order = 11)]
        public int numberOfPages { get; set; }
    }

    [DataContract]
    public class CloudPrinters
    {
        [DataMember (Order = 0)]
        public bool success { get; set; }
        
        [DataMember (Order = 1)]
        public List<CloudPrinter> printers { get; set; }
    }



    [DataContract]
    public class CloudPrintJob
    {
        [DataMember (Order = 0)]
        public bool success { get; set; }
        
        [DataMember (Order = 1)]
        public string message { get; set; }
    }



    internal class PostData
    {
        private const String CRLF = "\r\n";
        
        public string Boundary { get; set; }
        private List<PostDataParam> _mParams;
        
        public List<PostDataParam> Params
        {
            get { return _mParams; }
            set { _mParams = value; }
        }
        
        public PostData ()
        {
            // Get boundary, default is --AaB03x
            Boundary = "----CloudPrintFormBoundary" + DateTime.UtcNow;
            
            // The set of parameters
            _mParams = new List<PostDataParam> ();
        }
        
        public string GetPostData ()
        {
            var sb = new StringBuilder ();
            foreach (var p in _mParams)
            {
                sb.Append ("--" + Boundary).Append (CRLF);
                
                if (p.Type == PostDataParamType.File)
                {
                    sb.Append (string.Format ("Content-Disposition: form-data; name=\"{0}\"; filename=\"{1}\"", p.Name, p.FileName)).Append (CRLF);
                    sb.Append ("Content-Type: ").Append (p.FileMimeType).Append (CRLF);
                    sb.Append ("Content-Transfer-Encoding: base64").Append (CRLF);
                    sb.Append ("").Append (CRLF);
                    sb.Append (p.Value).Append (CRLF);
                }
                else
                {
                    sb.Append (string.Format ("Content-Disposition: form-data; name=\"{0}\"", p.Name)).Append (CRLF);
                    sb.Append ("").Append (CRLF);
                    sb.Append (p.Value).Append (CRLF);
                }
            }
            
            sb.Append ("--" + Boundary + "--").Append (CRLF);
            
            return sb.ToString ();
        }
    }
    
    public enum PostDataParamType
    {
        Field,
        File
    }
    
    public class PostDataParam
    {
        public string Name { get; set; }
        public string FileName { get; set; }
        public string FileMimeType { get; set; }
        public string Value { get; set; }
        public PostDataParamType Type { get; set; }
        
        public PostDataParam ()
        {
            FileMimeType = "text/plain";
        }
    }
}

Monday, January 14, 2013

Preferences in Monodroid.

Jared, a coder that's helping me out sometimes, went and found this gem.

Been trying to get him to post on here, but instead I'll post his code that he dug up for me.

Had to tweak what he put in, to work a bit cleaner in the app, but it was great research done,
and I really needed it for a deployment about a week ago.

            ISharedPreferences prefs = GetPreferences (FileCreationMode.Append);
            ISharedPreferencesEditor editor = prefs.Edit ();
            editor.PutString ("LoginName", creds);
            editor.Commit ();

This code will let you pretty much append anything you need via code into your preferences.

You just need to put in your string for the preference name.. and the value.  You can, of course, change the type a bit there in that editor variable.

User Management for Mobile Worlds.

Simple App Management Model.

I always like to start things out simply.  So, I've been working on this User Management Service, for mobile applications.  There are some columns missing.  Like LastLogin on the User.. etc.  Probably some tables for Application, if I were building an auto-updating Mobile Application service.  *coughs* Don't really want to get too much into the things I've left out on here at points.

The great thing about cloud work, is that you have no infrastructure.  I've seen a whole pile of nerds go gabby over how many servers etc that they manage, but once you commit capital to those resources, in a lot of ways it's like buying a new car.. just driving them off the lot, you lose value.  Not even that, if you have capital for those assets, then even worse from a business aspect, you have to have nerds to take care of that new ferrari server you've got parked in that rack.  That rack probably has AC cooling.  Why do the rack if you aren't going to cool your hardware off and risk component damage?  Then you need a locked room.  Not a great idea to have a ferrari, if you can't stop who takes it for a spin, right?  That's the problem with infrastructure, it starts to own you.

By staying up in the cloud, my servers get cheaper, the more competition there is for pricing, which happens pretty dang often (Thank you microsoft and amazon for being in a world domination tour, oh, Amazon is winning, MS, you better start making stuff as cheap as the competition, or you'll find that only C# sharp survives).

I'm going to throw some examples up here for components. I frequently use :

SendGrid.  Great service in Azure.  It's pretty much an add-in for your Azure account, and once you add that service to your account, you'll have the credentials to send your emails for your applications.

            SendGrid myMessage = SendGrid.GenerateInstance();
            myMessage.AddTo(u.UserEmail);
            myMessage.From = new System.Net.Mail.MailAddress("youremail", "youremaildisplayname");
            myMessage.Subject = "Welcome to {System}";
            string greeting = string.Format("Hello, {0}", u.FirstName);

            myMessage.Text = greeting + "\r\n" + "We are glad to have you in {System}.";

            // Create credentials, specifying your user name and password.
            var credentials = new NetworkCredential("credentialsgiveninsignupprocess", "");

            // Create an REST transport for sending email.
            var transportREST = SendGridMail.Transport.SMTP.GenerateInstance(credentials);

            // Send the email.
            transportREST.Deliver(myMessage);

Next comes to security.  I can't afford to have passwords in my account management system.  I can afford a salt and a hash.  So, here is the code for that.

        private static byte[] Hash(string value, string salt)
        {
            return Hash(Encoding.UTF8.GetBytes(value), Encoding.UTF8.GetBytes(salt));
        }

       private static byte[] Hash(byte[] value, byte[] salt)
        {
            byte[] saltedValue = value.Concat(salt).ToArray();
            
            return new SHA256Managed().ComputeHash(saltedValue);
        }

Oh, the return on that SHA-256, I just saved as varbinary (32).  I'm sure there are many different types you could use, but I was up at 1am in the morning, and when I finally got it working properly, I just called it quits for the night.

Two more simple utilities that I've found necessary, and are working quite well for me.  Remember to post on https folks.


Sunday, December 23, 2012

Simple Mono Droid Entry point for new features.


One of the things I've needed, in order to create a rapid development environment, is an entry point that is extensible.    Using this setup, I was able to easily throw in new features at a running pace.


public static class Selector
    {
        public static void Selected (string component,Activity act,int Id)
        {
            switch (component) 
            {
                case "Participant List":
                    var intent = new Intent();
                    intent.SetClass(act, typeof (ParticipantListActivity));
                    intent.PutExtra("Type","");
                    intent.PutExtra("Id","");
                    act.StartActivity(intent);
                break;
                case "Child Detail":
                    var childintent = new Intent();
                    childintent.SetClass(act, typeof (ChildDetailsActivity));
                    childintent.PutExtra("currentChildId",Id);
                    act.StartActivity(childintent);
                break;
                case "Parent List":
                    var parentintent = new Intent();
                    parentintent.SetClass(act, typeof (ParentListActivity));
                    act.StartActivity(parentintent);
                break;
                case "Scanner":
                var scannerintent = new Intent();
                scannerintent.SetClass(act,typeof(ScannerActivity));
                act.StartActivity(scannerintent);
                break;
                case "School List":
                    var schoolintent = new Intent();
                    schoolintent.SetClass(act,typeof(SchoolListActivity));
                    act.StartActivity (schoolintent);
                break;
                case "Kiosk":
                var kioskintent = new Intent();
                kioskintent.SetClass(act,typeof(LocationListActivity));
                act.StartActivity(kioskintent);
                break;
                default:
                break;


            }
        }
    }


public class Main : ListActivity
    {
        ProgressDialog progress;

        string[] Entries = { "Participant List","Parent List","Scanner","Kiosk"};

        protected override void OnCreate (Bundle bundle)
        {
            base.OnCreate (bundle);
            SetContentView (Resource.Layout.TextViewItem);

            this.ListAdapter = new ArrayAdapter<string>(this,Android.Resource.Layout.SimpleListItem1,Entries);

        }

        protected override void OnStart ()
        {
            base.OnStart ();
        }

        protected override void OnResume ()
        {
            base.OnResume();
        }

        protected override void OnListItemClick (ListView l, View v, int position, long id)
        {

            string place = ((ArrayAdapter<string>)this.ListAdapter).GetItem(position);
        
            Selector.Selected(place,this,0);
        }
    }

Rest Sharp MonoDroid, Post in Body.

   I needed to add an item in the body of a post via RestSharp in Mono Droid.  Luckily, the way I've built things, doesn't really expose any endpoints via code, for this reference.  So here is the code.. if you want to know how to post an object in the body of a Rest Sharp request.

public static Credentials Login(Credentials credentials)
        {
            var client = new RestClient();
            var request = new RestRequest();
            request.Method = Method.POST;
            var json = JsonConvert.SerializeObject(credentials);
            request.AddParameter("application/json; charset=utf-8", json, ParameterType.RequestBody);
            request.Resource = ServiceBase+string.Format(Data.Service.Login);

            RestResponse<Credentials> response = (RestResponse<Credentials>)client.Execute<Credentials>(request);
            Credentials item = new Credentials();
            JsonConvert.PopulateObject(response.Content,item);
            return item;
        }

Pretty simple, yes? -smiles-

On Boot Receiver in MonoDroid.



Sometimes your samples, for the technology you are using don't have a great example for what you need to accomplish.

Here is a working example for a class that uses a BroadcastReceiver to receive the On Boot Completed Event, and then start an Activity.

Get into your solution.  Right click on your Project, select Options. Go to Mono for Android Applications :



This is your class. Feel free to tweak the Intent to your own Activity class that you wish to start.

    [BroadcastReceiver] 
    [IntentFilter(new string[] { Intent.ActionBootCompleted }, Priority = (int)IntentFilterPriority.HighPriority)]
    public class BootBroadcastReceiver : BroadcastReceiver {

        public override void OnReceive(Context context, Intent intent) {
            Intent startServiceIntent = new Intent();

            startServiceIntent.SetClass(context, typeof(Login));
            startServiceIntent.AddFlags(ActivityFlags.NewTask);
            context.StartActivity(startServiceIntent);
        }
    }

I thought I needed to modify the AndroidManifest.xml.  Boy, was that wrong.  Just use the Attributes.  They will make your broadcast receiver automatically respond to the event.

A good link to check out. Blue Stacks. Android on PC and Mac.

Thursday, December 20, 2012

Useful Mono Droid Snippets.


Nowdays, everybody loves JSON.  Truth is.. I feel it is much easier to use in some regards for Web, and Mobile projects than XML, but there is something to be said for both data formats.

This is a snippet for retrieving any web response in JSON, via Rest Sharp in a Mono Droid, or Mono Touch environment, that you can then parse with your JSON Deserializer (Whatever flavor you prefer, hopefully one that supports AsParallel()).

This isn't the code I am using anymore.  As the first security layer is in place.  Below I have a post semi-related to the 2nd security layer, which is semi in-progress.. involving X509 certificates.

I also have made a model for a web service that will provide all User Application management functions for all mobile applications that I'll be developing.  I prefer the cloud.  It's cheap, I don't need anyone other than myself.  (Even though I'm a pretty decent sys admin).

        private static RestClient CutDownBloat()
        {
            var client = new RestClient();
            client.AddHandler("application/json; charset=utf-8",new RestSharp.Deserializers.JsonDeserializer());
            return client;
        }
        private static RestResponse<Object> CutDownCode(string url)
        {
            var request = new RestRequest();
            request.Method = Method.GET;
            request.Resource = url;
            var client = CutDownBloat();
            RestResponse<Object> response = (RestResponse<Object>)client.Execute<Object>(request);
            return response;
        }


In order to make a true secure system for a mobile application, you need a unique ID for the device attempting to access your services.

Just getting a unique device ID is a key component.


This is a snippet that will return a Unique Device ID for Android devices.


public static class DeviceData
    {
        public static string getDeviceID(Context context)
        {
            TelephonyManager tm = (TelephonyManager) context.GetSystemService(Context.TelephonyService);
            return tm.DeviceId;
        }
    }