Saturday, April 27, 2013

Gotta say, it's all about the App Store SEO.

I haven't been posting app figures, because they became abysmal. However, I think this release today will fix the course.  Also, did some upgrades on appearance, and had Jared help me out with some splash screens.  (Jared is awesome, he needs to do some posts on Android theming).



Pretty much have my next feature set lined up, along with the SEO tweaks for my next "attempt" at this brutal store environment.  The reason I can post this stuff, is because it takes so long to get your app approved.  See, I submitted my app last weekend.  So I have all week to make my next given set of features.  When the app is approved (I test pretty powerfully, so failure isn't really a big chance), then I have my next release ready.  I will play with the app tonight after the boys are in bed, and see if I can do anything more.. and then I'll submit. Anyways, time to give them a bath. See ya next post. : )

Thursday, April 25, 2013

Example of updating a SQLite DB using Xamarin Studio in C#

It took me longer than I'd like to piece this together so I'm sharing a simple example for anyone else looking to make a secure update to a local SQLite database in Android using C#.

static void UpdateDatabase(int primaryKey, string newText, int newValue)
{
 string path = Path.Combine (System.Environment.GetFolderPath (System.Environment.SpecialFolder.MyDocuments), "mydatabase.db");
 var db = new SQLiteConnection(path,false);
 string sql = "UPDATE MyTable SET MyTextColumn = ?, MyValueColumn = ? WHERE MyPrimaryKey= ?";
 string[] parms = new String [] {newText, newValue.ToString(), primaryKey.ToString() };
 var cmd = db.CreateCommand(sql, parms);
 cmd.ExecuteNonQuery();
}

More C# conversions of the Unity scripts for the Lynda.com Unity essentials course


Projectile Class

public class Projectile : MonoBehaviour {

public GameObject projectile;
public float FireRate = 0.5f;
public float Speed = 5f;
internal float nextFire;

void Update ()
{
if (Input.GetButton ("Fire1") && Time.time > nextFire)
{
nextFire = Time.time + FireRate;
GameObject clone = (GameObject)Instantiate(projectile, transform.position, transform.rotation);
clone.rigidbody.velocity = transform.TransformDirection(new Vector3(0,0,Speed));
Physics.IgnoreCollision(clone.collider, transform.root.collider); //stops projectile from colliding with player
}
}
}

Final Projectile Handler Class


public class ProjectileHandler : MonoBehaviour {

void Start ()
{
//Destroy(gameObject, 5);  // destroy object after set time
}

void Update () {

}

void OnCollisionEnter(Collision collison)
{
if (collison.transform.tag != "Dont Destroy")
{
//send message to collided object
collison.transform.SendMessage("BeenHit", SendMessageOptions.DontRequireReceiver);

//Debug.Log(collison.transform.name);

Destroy(gameObject, 1);
}
else
{
Destroy(rigidbody, 5);
//Debug.Log("stopped " + collison.transform.name);
}
}
}

DoorDamage Controller


public class DoorDamageController : MonoBehaviour {

public Collider doorJam;
public Collider wall;

void BeenHit()
{
//Destroy(gameObject, 1);
Physics.IgnoreCollision(doorJam.collider, transform.collider);
Physics.IgnoreCollision(wall.collider, transform.collider);
}
}

GameManager


public class GameManager : MonoBehaviour {

public GameObject fpc;

// Use this for initialization
void Start ()
{
//hide cursor
Screen.showCursor = false;

}

// Update is called once per frame
void Update ()
{
if (Input.GetKeyDown("escape"))
{
Screen.showCursor = !Screen.showCursor;
fpc.SendMessage("ToggleInput", Screen.showCursor);
}
}
}







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.

C# versions of the Lynda.com Unity course scripts

I recently completed the Unity 3.5 essentials course on Lynda.com in order to get past the limitations of the drag and drop features.  The course uses Javascript, but I prefer C#.  I'm putting my converted code here for anyone else that would like it. 

I use the internal instead of private access modifier as this will hide the variable from the inspector, but still make it available to other classes.


Final RotationController class.

using UnityEngine;
using System.Collections;

public class RotationController : MonoBehaviour {
public bool RotationState = true;
public float RotationSpeed = 20f;
internal float initialSpeed;
// Use this for initialization
void Start () {
initialSpeed = RotationSpeed;
}
// Update is called once per frame
void Update ()
{
if(RotationState && RotationSpeed > 5f)
{
transform.Rotate(0, RotationSpeed * Time.deltaTime, 0);
}
}
void OnMouseDown()
{
RotationState = !RotationState;
RotationSpeed -= 0.5f;
if (RotationSpeed < 0)
RotationSpeed = initialSpeed;
}
}

Final ReportDistance Class

using UnityEngine;
using System.Collections;

public class ReportDistance : MonoBehaviour {
public Transform targetObject;

// Use this for initialization
void Start () 
{
targetObject = GameObject.Find("First Person Controller").transform;
}
// Update is called once per frame
void Update () {
if (targetObject)
{
float distance = Vector3.Distance(targetObject.position, this.transform.position);
//Debug.Log("Distance to target object: " + distance);
}
}
}

Final RayCaster Class

using UnityEngine;
using System.Collections;

public class RayCaster : MonoBehaviour {
RaycastHit hit; //holds properties of detected object

// Use this for initialization
void Start () {
}
// Update is called once per frame
void Update () 
{
if(Physics.Raycast(transform.position, transform.forward, out hit, 10))
Debug.Log("There is a " + hit.transform.name + " something in front of the object!");
else Debug.Log("There is nothing within 10 metres!");
}
}

Saturday, April 20, 2013

UIImage to PDF.


Found this on a StackOverflow post, tweaked for sanity's sake (mine):

Link:   UIImage to PDF

Lots of work to do this weekend.  Took a minute to throw this out here.

public static byte[] CreatePDF (UIImage image)
{
        NSMutableData data = new NSMutableData();
        UIGraphics.BeginPDFContext(data, new RectangleF(new PointF(0,0), image.Size), null);
        UIGraphics.BeginPDFPage(new RectangleF(new PointF(0,0), image.Size), null);
        image.Draw(new RectangleF(0, 0, image.Size.Width, image.Size.Height));
        UIGraphics.EndPDFContent();

        using (NSData imageData  = data)
        {
            Byte[] myByteArray = new Byte[imageData.Length];
            System.Runtime.InteropServices.Marshal.Copy (imageData.Bytes, myByteArray, 0, Convert.ToInt32(imageData.Length));
            fs = new MemoryStream(myByteArray);
        }
        return fs.ToArray();

}

Friday, April 19, 2013

Machinarium.

My son, Logan, loves the game Machinarium.

Our code for the final puzzle was a little different than the walkthrough. (Sometimes he gets frustrated with difficult games.. and gets all annoyed, overall it's pretty cute when he does it, but it can get hard to deal with after 30 minutes)

For a good part of the game, I refused to use the walkthrough.  Then that bridge part, with the cat.. I was just lost.. Maybe it was just how many of those puzzles I'd solved that weekend, but I ended up being weak.. and going to look up how to do it.. then of course.. once you do it.. you can't easily stop.

1, 2, 3, 4, 1, 2, 5 was our code on the IPad 2.

Wednesday, April 10, 2013

Google Cloud Print Component is now live.

Victory dance!

EVOLVE CONFERENCE!!!!1111!!!!

Looks like I'm headed to Evolve.  The Xamarin Conference.

I'm excited.  I think I only got the free pass, because I threatened to camp outside the conference rooms. : )

I had a plane ticket.. because I had to pay for it from a previous employer.  I will end up staying in a hostel, because the budget is tight.

I am happy. Things are going well at work, and I'll have quite a few use cases to finish to go to this conference, but to be honest.. I know even right now.. that it won't get in my way.  This person I am now, isn't the same person that was around even 4-5 months ago.  I don't know whether to feel bad about that, or to enjoy it.  My obligation is the same as it always was, I just feel differently about the weight of it.  I now do what I do, for the enjoyment of it, not because it must be done.

This conference was everything I wanted.  Very grateful right now.


Thursday, April 4, 2013

Dynamic Data Entities Localization DateTime Field Template / DateTime_Edit



Had a problem with Localization for DateTime from a UTC set date, the solution was in the DateTime.ascx, and in the DateTime_Edit.ascx, I merely had to put an override for the FieldValue.

Of course, it's best practice to mark up your EF column with [DataType(DataType.DateTime)]

public override object FieldValue
        {
            get
            {
                return ((DateTime)base.FieldValue).ToLocalTime();
            }
            set
            {
                base.FieldValue = ((DateTime)value).ToUniversalTime();
            }
        }