23 December 2013

Android show contact email addresses

So this is something in Android I thought would be really simple but quite frankly, wasn't. I want to get a list of all email addresses in my phone and display them in a list. If one is to use ContactsContract.CommonDataKinds.Email.CONTENT_URI without filter you basically get every email address you've ever emailed. Not ideal. I am (in this case) looking for only our saved Google contacts. We can do this query in the UI thread, which works fine but if you have several hundred contacts that'll kill the app. So we're going to use LoaderManager. First we setup out fragment:

public class FragmentMain extends Fragment implements LoaderManager.LoaderCallbacks{

 ArrayList mFriends = new ArrayList();

...
}

Now we need to setup our createLoader method to get the data and onLoadFinished to put the data into the UI. The selection here is very important as it limits the query to the visible contacts: String my_selection = ContactsContract.Contacts.IN_VISIBLE_GROUP + " = '1'";.
Next step is very simple, in the onLoadFinished we loop through the available data, adding each email address to an ArrayList.


 @Override
 public Loader onCreateLoader(int arg0, Bundle arg1) {
  //Sort by email address no case
  final String my_sort_order = ContactsContract.CommonDataKinds.Email.DATA + " COLLATE NOCASE ASC";
  String my_selection = ContactsContract.Contacts.IN_VISIBLE_GROUP + " = '1'";
  String[] eproj = new String[]{
   ContactsContract.Contacts._ID,
   ContactsContract.CommonDataKinds.Email.DATA};
  Uri uri = android.provider.ContactsContract.CommonDataKinds.Email.CONTENT_URI;
  //Query all emails in contacts
  return new CursorLoader(getActivity(), uri, eproj, my_selection, null, my_sort_order);
 }

 @Override
 public void onLoadFinished(Loader arg0, Cursor data) {
  
  if (data != null && data.moveToFirst()) {
   //Loop through cursor
   while (!data.isAfterLast()) {
    //get Email address
    String myemail = data.getString(data.getColumnIndex(ContactsContract.CommonDataKinds.Email.DATA));
    if(!mFriends.contains(myemail)){
     //Add email to arrayList
     mFriends.add(myemail);
    }
    
    data.moveToNext();
   }
  }
  //load friends into ui
  loadFriends();
 }

 @Override
 public void onLoaderReset(Loader arg0) {
  //Not Used
 }

Last but not least we load the data into our listview. Now you can of course, should you desire, create a custom Adapter and implement your own item view, but that's a blog post for another day.


 private void loadFriends(){
  //load arraylist into adapter.
  ArrayAdapter adapter = new ArrayAdapter(getActivity(), android.R.layout.simple_list_item_1, android.R.id.text1, mFriends);
  mFriendsList.setAdapter(adapter);
 }

Oh and one more thing, don't forget your permissions :)
<uses-permission android:name="android.permission.READ_CONTACTS" />

14 October 2013

Android Nav Drawer / Sliding Menu

If you've seen those side bar sliding menu's in Android you may have found them pretty useful. Facebook has used them to good affect with its left and right nav drawer menus. If you've tried to create them you'll no doubt know they're a pain. So many different versions of Android don't make it easy and the complexities of fragments make it tricky at best. However I have recently discovered a library by Jeremy Feinstein which makes it incredibly easy. So I can't claim I did much work here, but I did implement it, which (IMHO) his docs don't do brilliantly. Anyway his work is terrific, so give it a try http://jeremyfeinstein.com/

First things first, you'll need the Google Support Library. Then download Jeremy's library from github https://github.com/jfeinstein10/SlidingMenu. Get both of these librarys set up in Eclipse or Android Studio, whichever one you use. You'll need to make sure they compile with no errors. Word of advice, check the build target, ensure its the latest version of Android and the project is marked as a library.

Now create your new project and include both the libraries. Start with the easy bit and create to layout xml files. One for the sliding menu and one for the main page. The main page is whatever you want, here's my menu file though in case it helps FragmentMenu.xml:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:orientation="vertical" >

    <TextView
        android:id="@+id/fragment_menu_btn_animal"
        style="@style/MenuButton"
        android:drawableLeft="@drawable/animal"
        android:text="@string/muppet_animal" />

    <View
        android:layout_width="match_parent"
        android:layout_height="1dp"
        android:background="@color/spacer_menu_top" />

    <View
        android:layout_width="match_parent"
        android:layout_height="1dp"
        android:background="@color/spacer_menu_bottom" />

    <TextView
        android:id="@+id/fragment_menu_btn_gonzo"
        style="@style/MenuButton"
        android:drawableLeft="@drawable/gonzo"
        android:text="@string/muppet_gonzo" />

</LinearLayout>

Next create a FragmentMenu.java file, nothing ground breaking here:
package com.example.newnavbartest;

import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.view.LayoutInflater;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.widget.Toast;

public class FragmentMenu extends Fragment{

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        return inflater.inflate(R.layout.fragmentmenu, container, false);
    }
    
    @Override
    public void onActivityCreated(Bundle savedInstanceState) {
        super.onActivityCreated(savedInstanceState);
        
        getView().findViewById(R.id.fragment_menu_btn_animal)
        .setOnClickListener(new OnClickListener() { 
            public void onClick(View v) {  
                Toast.makeText(getActivity(), "Animal", Toast.LENGTH_SHORT).show();
            }
        });

        getView().findViewById(R.id.fragment_menu_btn_gonzo)
        .setOnClickListener(new OnClickListener() { 
            public void onClick(View v) {  
                Toast.makeText(getActivity(), "Gonzo", Toast.LENGTH_SHORT).show();
            }
        });
    
    }
    
}

Last and most important is the main activity file, this is where we control the sliding menu library:
package com.example.newnavbartest;

import com.jeremyfeinstein.slidingmenu.lib.SlidingMenu;

import android.os.Bundle;
import android.support.v4.app.FragmentActivity;
import android.support.v4.app.FragmentTransaction;

public class MainActivity extends FragmentActivity {

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setTitle(R.string.app_name);
        // set the content view
        setContentView(R.layout.activity_main);

        // configure the SlidingMenu
        SlidingMenu menu = new SlidingMenu(this);
        menu.setMode(SlidingMenu.LEFT);
        menu.setTouchModeAbove(SlidingMenu.TOUCHMODE_FULLSCREEN);
        menu.setShadowWidthRes(R.dimen.shadow_width);
        menu.setShadowDrawable(R.drawable.shadow);
        menu.setBehindOffsetRes(R.dimen.slidingmenu_offset);
        menu.setFadeDegree(0.35f);
        menu.attachToActivity(this, SlidingMenu.SLIDING_CONTENT);
        menu.setMenu(R.layout.activity_default);
        
        FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
        ft.add(R.id.activity_default_fragment_container, new FragmentMenu(), FragmentMenu.class.getSimpleName());
        ft.commit();
    }
    
}



Hopefully this helps! Here's the github of this project: https://github.com/jimbo1299/navdrawer

15 August 2013

Android Action Bar Compat


Action Bar Compat is an Android tool released by Google at I/O 2013.
http://android-developers.blogspot.ca/2013/08/actionbarcompat-and-io-2013-app-source.html

If you add a standard action bar to your Android project, you're forced to upgrade your minimum SDK version to 3.0, (API level 11 Honeycomb). This was when Google added the action bar. However if you want to support older versions of Android in your app then you can now use Compat. This enables you to drop back to Android 2.1 Eclair (API level 7).

Figuring out Action Bar Compat is not the easiest of tasks and requires quite a few steps.


Setup Support Library
http://developer.android.com/tools/support-library/setup.html

Action Bar Compat runs off a separate library that you need to install in your eclipse / studio workspace. Follow the steps in the above link carefully. You'll want to use the drop down "Adding libraries with resources" and follow those instructions. Once you're done you should have a new project named android-support-v7-appcompat in the workspace with no errors.
I had to modify my project.properties file to use the latest sdk:
target=android-18

Your Project

Now you can obviously create a new project or use an existing one. You'll want to make sure you right click on your project, click properties, click Android and then verify / change the following things:

  • You need to add the android-support-v7-appcompat project as a library.
  • You need to make sure the project build target is the same for your project as it is for android-support-v7-appcompat. This is currently Android 4.3.














Now you can start changing the contents of the project. First the res/menu/menu.xml file has a couple of small changes:

  • The XML namespace becomes:
    <menu xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:support="http://schemas.android.com/apk/res-auto" >
  • The item attribute android:showAsAction="ifRoom|withText" becomes support:showAsAction="ifRoom"
Next the Manifest.xml.

  • Change the application theme, from this:
    • android:theme="@style/AppTheme"
             to
    • android:theme="@style/Theme.AppCompat"
Now open up your MainActivity.java file and we need to change a few things in here:

  • Change the extends to use ActionBarActivity
    • public class ... extends Activity
            becomes
    • public class ... extends ActionBarActivity
  • Replace any onCreateOptionsMenu you may have with a new one:
    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        // Inflate our menu from the resources by using the menu inflater.
        getMenuInflater().inflate(R.menu.main, menu);

        return true;
    } 
  • The onOptionsItemSelected should be the same.
  • You'll also need to import the following class:
         import android.support.v7.app.ActionBarActivity;
    But head Google's warning:


Caution: Be certain you import the ActionBar class (and related APIs) from the appropriate package:
  • If supporting API levels lower than 11:
    import android.support.v7.app.ActionBar
  • If supporting only API level 11 and higher:
    import android.app.ActionBar

That's about it, you should be ready to cook.

This is Android 2.1 (API Level 7) Without Action Bar Compat:




This is Android 2.1 (API Level 7) with Action Bar Compat:




Easy as that!
Here's my git repo for this example: https://github.com/jamessolo12/actionbarcompat You can find Google's sample here: /sdk/samples/android-18/ui/actionbarcompat/Basic

08 August 2013

Android, extending listView functinality


Android listViews are pretty useful and pretty simple. You have to get your head around some sort of adapter, but that's no huge issue.

However I've previously never bothered to find out how to get more than one column on a listView. Luckily this is much easier than I first thought. My example uses contentProvidors to setup the cursor, but I think this should work with DB stuff as well. Given a bit of hocus pocus.

I'm not going to go into the contentProvidor stuff here as it's a big subject and developer.android do a pretty good job:
http://developer.android.com/guide/topics/providers/content-provider-basics.html

First setup your activity_main.xml layout file:

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
 xmlns:tools="http://schemas.android.com/tools"
 android:layout_width="match_parent"
 android:layout_height="match_parent">
 
 <ListView
  android:id="@+id/listView1"
  android:layout_width="wrap_content"
  android:layout_height="350dp"
  android:layout_alignParentBottom="true"
  android:layout_centerHorizontal="true" >
 </ListView>

</RelativeLayout>


Next add a new xml file to the res/layout folder (mine is named contacts_single.xml):

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
 android:layout_width="match_parent"
 android:layout_height="match_parent"
 android:orientation="horizontal" >

 <TextView
  android:id="@+id/name_entry"
  android:layout_width="100dp"
  android:layout_height="wrap_content" />
 
 <TextView
  android:id="@+id/number_entry"
  android:layout_width="100dp"
  android:layout_height="wrap_content" />

</LinearLayout>


Now move to the MainActivity or wherever your display function will be and you'll need something like this:

private void outputCursor(){
 // Defines a list of columns which we have defined in our cursor, and will be output to listView
 String[] mWordListColumns =
 {
  ContactsContract.Contacts._ID,
  ContactsContract.Contacts.DISPLAY_NAME_PRIMARY
  
 };

 // Defines a list of View IDs. These are IDs of textViews defined in a serperate layout file
 int[] mWordListItems = { R.id.name_entry, R.id.number_entry};

 // Creates a new SimpleCursorAdapter
 SimpleCursorAdapter mCursorAdapter = new SimpleCursorAdapter(
  getApplicationContext(),   // The application's Context object
  R.layout.contacts_single,   // A layout in XML for one row in the ListView
  mCursor,     // The result from the query
  mWordListColumns,    // A string array of column names in the cursor
  mWordListItems,     // An integer array of view IDs in the row layout
  0      // Flags (usually none are needed)
 );

 // Sets the adapter for the ListView
 ListView myListView = (ListView) findViewById(R.id.listView1);
 myListView.setAdapter(mCursorAdapter);
}

That should be all you need. Note the mWordListItems is passed into the adapter and the R.layout.contacts_single reference, telling the adapter to use these custom elements to display its contents. Then we get the ListView from the original activity and set the adapter. Simples!

06 August 2013

Android databse SqlLite and SQL Injection

SQL Injection is one of my favourite topics, sad but true. I think SQL injection is a very clever way of deceiving apps. This then encourages developers to be equally clever and thorough in their jobs to protect their data. I'm not for a moment endorsing such practices, what I'm saying is good developers should be aware of the possibilities.

In my last blog article I wrote a very brief introduction to SqlLite in Android.
http://webdeveloperpadawan.blogspot.ca/2013/07/android-app-using-database-sqllite.html

In this I deliberately left in some weak code so I could write a follow up on SQL injection. Look carefully at this string:

String DATABASE_ADD_USER  = "insert into "  + TABLE_NAME + " (muppetname) values (";

Obviously very susceptible to injection. If a user wrote

'; drop table theusers; --

We'd have a problem. Now fortunately database.execSQL() doesn't allow us to run more than one sql command in one execution. From developer.android.com:
Execute a single SQL statement that is NOT a SELECT or any other SQL statement that returns data.
In some ways this limits the potential of SQL injection, but we don't want to rely on that and it is horribly bad practice. Lets try it on our app and see what happens, paste the above (drop table statement) into the pop-up that appears when you click the btnFuzzy. You'll see your app crash and a SQLException in logCat.

In coldFusion we have a very useful tag called cfqueryparam: http://livedocs.adobe.com/coldfusion/8/htmldocs/help.html?content=Tags_p-q_18.html This simple tag gives us basic protection from injection and even allows us to specify the datatype. Although we should always clean our user input anyway :) Android has something very similar, allowing us to insert data using database.insert.

All we have to do is slightly ammend our insert user function:

 public void addNewUserProperly(SQLiteDatabase database, String name){
     ContentValues values = new ContentValues();
     values.put("muppetname", name);
     database.insert(TABLE_NAME, null, values);
 }

Now you'll see we've hardly changed anything, we use contentValues to store a set of values, the column name and the value. Then we insert that with database.insert. Super simple. If we re-run this and try our SQL injection trick, no more critical error :)

Hope this is of some use.

31 July 2013

Asus Zenbook with Ubuntu - part 2


Last time I blogged about this, I'd managed to dual boot Windows 8 and Ubuntu. Both were running off the large capacity HDD on my zenbook, Windows was using the 24Gb SSD as a cache drive. Ubuntu wasn't using it at all, and I noticed this in boot speeds. After a few weeks of this I hadn't booted into Windows 8 once so I decided to make the leap of faith and re-install Ubuntu over top of everything. Death to Windows 8!

I used the same method as before, go into UEFI, plug in the Ubuntu install key, change nothing and save and exit. Then immediately hold escape. This gave me the option to boot from USB and of course select install Ubuntu.

Ubuntu install started and I had to pick my language, wifi and a few other normal things. Then came the selection screen for where to install Ubuntu, this is the step I was more interested in. Ubuntu offered the choice to erase everything, or dual boot, etc etc. I was after "something else" down at the bottom. Basically the advanced setup. This allows you to customize where each piece of Ubuntu is installed, what extra partitions are setup and how.

This was quite advanced, a little tricky and quite a bit of background reading was required. This is a page I leaned heavily on for some advice:

http://askubuntu.com/questions/234111/how-to-boot-ubuntu-from-ssd-drive-which-cannot-be-selected-as-boot-device

I basically decided to install the OS on the SSD and install other crucial parts on the HDD. My reasoning being from what I've read and experienced, the SSD isn't bootable (which is lame). However booting off the HDD and then utilising the SSD for important file system reads works just as well.

To cut a long story short, after a considerable amount of time experimenting with partitions, I've now settled on, and have working the following partitions:

  • SSD - filesystem. Whole thing set up as /
  • HDD
    • 10Mb - BIOS Boot
    • 250Mb - EFI Boot
    • 200Mb - /Boot
    • 3Gb /Linux Swap file
    • Free space
That's about it, I had to repeat the method I did last time of finishing the install, then booting off the USB again, going into try Ubuntu and running boot repair. However that was easy this time and after that it all seemed to work!

Hope it's of some use.



29 July 2013

Android app using database sqlLite

I created a cute little test app today to try out a few database concepts on Android. Thankfully it's really easy and there are some great tutorials out there. Anyway some of the concepts are really useful so I thought I'd jot down my findings.

First I created my new Android project ignore the MainActivity for now. I create a pretty standard Muppet.java class. I shan't patronise you with the code, int ID, String name and getters and setters for each. Then I create a new class called MySqlLiteHelper.java this is what will do the db interaction for us.

MySqlLiteHelper.java:
import java.util.ArrayList;
import java.util.List;

import android.content.Context;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
import android.util.Log;

public class MySqlLiteHelper extends SQLiteOpenHelper {

 private static final String DATABASE_NAME  = "muppets.db";
 private static final int DATABASE_VERSION = 1;
 private static final String TABLE_NAME  = "theusers";

 // Database creation sql statement
 private static final String DATABASE_CREATE  = "create table " + TABLE_NAME + " (userid integer primary key autoincrement, muppetname text not null);";
 // DO NOT DO THIS IN YOUR CODE:
 private static final String DATABASE_ADD_USER  = "insert into "  + TABLE_NAME + " (muppetname) values (";
  
 
 public MySqlLiteHelper(Context context) {
  super(context, DATABASE_NAME, null, DATABASE_VERSION);
 }


 @Override
 public void onCreate(SQLiteDatabase database) {
  database.execSQL(DATABASE_CREATE);
 }
 

 @Override
 public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
  Log.w(MySqlLiteHelper.class.getName(), "Upgrading database from version " + oldVersion + " to " + newVersion + ", which will destroy all old data");
  db.execSQL("DROP TABLE IF EXISTS " + TABLE_NAME);
  onCreate(db);
 }
 
 
 public void addNewuser(SQLiteDatabase database, String name){
  // DO NOT DO INSERTS LIKE THIS IN YOUR CODE. FIND OUT WHY I THE NEXT ARTICLE.
  String insertString = DATABASE_ADD_USER + "'" + name + "');";
  database.execSQL(insertString);
 }
 
 
 public List getAllUsers(SQLiteDatabase database){
  List muppets = new ArrayList();
  String[] columns = {"userid","muppetname"};

  Cursor cursor = database.query(TABLE_NAME, columns, null, null, null, null, null);

  cursor.moveToLast();
  while (!cursor.isBeforeFirst()) {
   Muppet muppet = cursorToMuppet(cursor);
   muppets.add(muppet);
   cursor.moveToPrevious();
  }
  // Make sure to close the cursor
  cursor.close();
  return muppets;
 }
 
 
 private Muppet cursorToMuppet(Cursor cursor) {
  Muppet muppet = new Muppet();
  muppet.setMuppetId(cursor.getInt(0));
  muppet.setMuppetName(cursor.getString(1));
  return muppet;
 }
 
} 
  • MySqlLiteHelper - This function is the constructor, on initialization it will create the DB.
  • onCreate - This function created the database table by executing the static string at the top.
  • onUpgrade - I think this function is pretty clever, if you change the db version number, it'll self upgrade! Amazeballs!
  • addNewuser - This is an ugly way to insert a user, I'll change this later.
  • getAllUsers - Here we're creating a cursor and querying the db for all the users. Then we're reversing through the cursor and putting the user object into a list. I opted to reverse the list so new Muppets show up at the top. Although it's quite easy to traverse it normally and have new users at the bottom.
One quick thing that's important to mention is we're using a function in Muppet.java to force the fragment to show the muppet name, instead of the object id.

@Override
public String toString() {
 return name;
}


Our next step is to create the layout file. As an additional step I've included a fragment. This lets us compartmentalise our layout neatly. If you want to just dump a listView on the layout, you could also do that quite easily.
 <Button
  android:id="@+id/btnKermit"
  android:layout_width="wrap_content"
  android:layout_height="wrap_content"
  android:layout_alignParentLeft="true"
  android:text="Insert Kermit" />

 <Button
  android:id="@+id/btnFuzzy"
  android:layout_width="wrap_content"
  android:layout_height="wrap_content"
  android:layout_alignParentRight="true"
  android:text="Insert Fuzzy" />

 <Button
  android:id="@+id/btnRefresh"
  android:layout_width="wrap_content"
  android:layout_height="wrap_content"
  android:layout_below="@+id/btnKermit"
  android:layout_centerHorizontal="true"
  android:layout_marginTop="19dp"
  android:text="Refresh" />
 
 <fragment
  android:id="@+id/fragment1"
  android:name="com.example.testdata.ShowFragment"
  android:layout_width="wrap_content"
  android:layout_height="wrap_content"
  android:layout_alignParentBottom="true"
  android:layout_below="@+id/btnRefresh"
  android:layout_centerHorizontal="true" />
Notice that this fragment is pointing directly to our ShowFragment.java class which we'll create now:
import java.util.List;

import android.database.sqlite.SQLiteDatabase;
import android.os.Bundle;
import android.view.View;
import android.widget.ArrayAdapter;
import android.widget.ListView;
import android.app.ListFragment;

public class ShowFragment extends ListFragment {

 private SQLiteDatabase database;
 private MySqlLiteHelper dbHelper;
 
 @Override
 public void onActivityCreated(Bundle savedInstanceState) {
  super.onActivityCreated(savedInstanceState);
  
  dbHelper = new MySqlLiteHelper(getActivity());
  database = dbHelper.getWritableDatabase();
  
  showAll();
 }
 
 public void showAll(){
  List values   = dbHelper.getAllUsers(database);
  final ArrayAdapter adapter = new ArrayAdapter(getActivity(), android.R.layout.simple_list_item_1, values);
  
  setListAdapter(adapter);
 }

 @Override
 public void onListItemClick(ListView l, View v, int position, long id) {
  // Do something with the data
 }
}
This should be pretty straightforward. OnActivityCreated we get the database instance, then call showAll. showAll() calls getAllUsers and puts the results in a List. This List is then converted to an adapter and we use setListAdapter to show the results in the fragment.

Bingo!
The main activity doesn't do anything special, it has a couple of buttons for adding new muppets, basic listeners which call
dbHelper.addNewuser(database, "Kermit");

Oh and there's a refresh button which updates the fragment:
 public void refresh(){
  //get fragment to refresh
  ShowFragment viewer = (ShowFragment) getFragmentManager().findFragmentById(R.id.fragment1);
     viewer.showAll();
 }

You're done! Super easy, hope it helps.





24 July 2013

Google Play Game Services


I've previously created my own custom built high scores add on for my Android app, frankly it was pretty rubbish. It was local only, not very pretty and had no public competition element. There are a few third party apps but they cost money. That is until at Google IO Google announced Google Play Game Services. I thought I'd take a look and I was incredibly impressed.

http://developer.android.com/google/play-services/games.html

Game Services allows you to instantly integrate a leaderboard into your app. It does this using Google + which means your users can share their scores with their circles, specific friends or of course with the public. I love this because just thinking about creating a user id for every user and a server side backend to deal with all that makes me shudder. Plus you can add in achievements which is pretty cool too.

So if you want to get started adding play services I very much recommend downloading Google's sample app "Type-a-Number":

https://developers.google.com/games/services/android/quickstart

Then run through the steps to get the API set-up on Google's developer console and of course provides a sample app and code to study. I really recommend you study this and get a good grasp on how it all works. I'm not going to run through all the code here, as Google have already done that. The same applies to the API, you do need to do a bit of setup on Google's developer console. Just make sure you copy the IDs of your game service and your leaderboard into your android project. Preferably in the same way Google suggest with an ids.xml file.

You're going to need to set-up eclipse and your project with Google Play Services Library which I already had for Google Maps anyway. The sample app uses the Base Game Utils library, which isn't totally necessary, but it does make things a little simpler. Again, all steps are covered in the quickstart.

The first thing is to get the Google Plus button working. This is a simple case of adding in the com.google.android.gms.common.SignInButton button to your layout file.
Then add a listener:

//Listener for Sign in
findViewById(R.id.sign_in_button).setOnClickListener(new View.OnClickListener() {
    public void onClick(View v) {
        beginUserInitiatedSignIn();
    }
});

Now beginUserInitiatedSignIn() is a function in Base Game Utils which deals with the Google + magic. It does have a callback function though which you can utilise, here's mine:

@Override
public void onSignInSucceeded() {
    Toast.makeText(this, "Signed in", Toast.LENGTH_SHORT).show();
    
    mShowSignIn = false;
    updateUi();

}

UpdateUi() handles hiding the sign in button and showing the sign out button.

Last but not least we need to push our scores.

getGamesClient().submitScore(getString(R.string.leaderboard_highscores),intScore);

It's spectacularly easy to do.

There are however a few things I've learnt:
  1. Be very wary of your certificate. You'll need to make sure the SHA1 hash you use is the same you export your Android project as the one you enter on the game services API.
  2. When you come to release this, if you've been using your debug certificate you'll need to delete your game services on the API and start it all over again. I've tried many times to tweak the SHA1 in an active game service but it always breaks. So best to start fresh with a production ready certificate and use it for the API as well.
  3. The IDs you get from play services must be copied exactly to your ids.xml file and your manifest must have a line like this:
    <meta-data android:name="com.google.android.gms.games.APP_ID" android:value="@string/app_id" />

  4. If you want to delete your scores or change the IDs you use for the game services or leaderboard you need to goto:
    Settings -> Google -> Google + -> Apps With Google + Sign In -> xx_AppName_xx -> Disconnect App
    You'll get the option here to delete your scores. This can be a bit temperamental, so change IDs only if you're really stuck.

One last thing worth mentioning, and its addressed to Google, whom I'm sure study my blog every day! When one looks at the achievements board, you can't expand the achievement to get the full description of what is required. On a phone, this means you'll never know what's required.

Thanks and good luck.

15 July 2013

Asus Zenbook and Ubuntu


I recently bought a shiny new Asus Zenbook, which which I'm delighted. However it came with Windows 8 and try as I might the sales guy wouldn't offer me anything else. I've recently blogged about my intense hatred for all things Windows 8 related. So I've decided to put Ubuntu on it, for now I'm dual booting. With past experience Ubuntu is so awesome, plus quick and easy to install I might decide to go back and clobber Windows 8 altogether.

The following are a few hints and tips I picked up if you try something similar. The bulk of the problem arises around the new version of BIOS called UEFI. This feels like an Intel thing that's been designed specifically for Windows and the rest of the world now has to catchup. Anyhow, I digress.
http://en.wikipedia.org/wiki/Unified_Extensible_Firmware_Interface

The first thing I did was backup Windows 8. Just in case I needed to roll back. Then of course create a Ubuntu USB Install Key.

  1. Create a system image on a external hard drive or DVDs
    http://www.techrepublic.com/blog/window-on-windows/restore-windows-8-with-system-image-recovery/7464
  2. Create a Bootable USB Reovery Key
    http://www.techrepublic.com/blog/window-on-windows/create-a-recovery-drive-in-windows-8/7261

  3. Create a Bootable Ubuntu Install Key
    http://www.ubuntu.com/download/desktop/create-a-usb-stick-on-windows

Thanks to Greg Shultz for those great articles.

That's the easy bit. In the good old days of BIOS that was basically it. You could insert your USB Ubuntu key and reboot, possibly tweaking BIOS boot order slightly. Sadly this is where UEFI makes things very difficult.

First I had to hold delete to get into UEFI which can easily be missed as the setup window gets smaller all the time. Then you need to disable fast boot and secure boot.Now plug in your Ubuntu USB key and save and restart. As soon as you're out of UEFI hold down the escape key. This brings up the boot options. Hopefully your USB key will be listed there. If not select "Enter Setup" and try again. Sometimes this takes a few goes.

Once you've got the USB Key to boot, you can install Ubuntu as a dual boot or "Full Windows annihilation" mode. This is all pretty self explanatory.

When you finish you'll be asked to reboot. When I did this I went straight back into Windows. Lame.

To combat this I went back into UEFI, didn't change anything, but did a save and exit (F10). Then again held the scape key and selected my USB key from the boot menu. Instead of install, this time select trial, or run from usb key. This gets you running a version of Ubuntu without installing anything. From there follow these instructions:
https://help.ubuntu.com/community/Boot-Repair

This will re-install the boot loader that windows 8 has interfered with. As I mentioned I did a dual boot, so it re-installed GRUB and allowed me to select my desired OS on boot.

That should be it. Remove your USB key and you should be running Ubuntu.

08 July 2013

Android Spinner With Linked Values

In all the languages I've used I've had need for a drop-down. However they all seem to call it something different. .net calls it a combo box, html calls it a select tag and Android appears to call it a Spinner. Oh well! Normally I've used it as a key value pair. That is to say the string you select, isn't normally the same as the value you pass in the result. For example

<select>
    <option value="42">Volvo</option>
    <option value="24">Ford</option>
</select>

Android makes this a little tricky as it doesn't offer the same functionality, but using a hashmap provides a good way to go keep a map of options and their corresponding value.


private String[]            arrMuppetNames  = {"Kermit","Gonzo","Fuzzy","Animal"};
HashMap<String, Integer>    hashMuppets     = new HashMap<String, Integer>();

Setting up the hashmap is fairly trivial using the put method. In this example I used a set of if statements with hard coded values. Normally you'd get your values from a web service or a db call.

One problem I encountered with this method is when you setup your OnItemSelectedListener it will get fired immediately when  you start your application. Technically this is correct as something has been selected onLoad, but not normally desirable activity. So to combat this I've added in a --please select-- value and ignored this element. This is fairly common practice in HTML and works in Android too.

So this is the function that builds the spinner, note we're creating a new array with the zero value set to --please select--.

private void setSpinnerContent(String arrMuppets[]){
    Spinner spinner            = (Spinner) findViewById(R.id.muppets_spinner);
    String arrNewArray[]    = new String[arrMuppets.length + 1];
    
    //Add please select to spinner
    arrNewArray[0]    = this.getString(R.string.select_please);
    for(int i=0; i < arrMuppets.length; i++){
        arrNewArray[i+1]    = arrMuppets[i];
    }
    
    //Application of the Array to the Spinner
    ArrayAdapter<String> spinnerArrayAdapter = new ArrayAdapter<String>(
            this,   
            android.R.layout.simple_spinner_item, 
            arrNewArray
    );
    spinnerArrayAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item); 
    spinner.setAdapter(spinnerArrayAdapter);
}

Then last of course is the selected item listener

private Spinner.OnItemSelectedListener spinnerListener = new Spinner.OnItemSelectedListener(){
    @Override
    public void onItemSelected(AdapterView<?> arg0, View arg1,int arg2, long arg3) {
        Spinner        my_spinner    = (Spinner) findViewById(R.id.muppets_spinner);
        
        //arg 3 is index, if 0 it means they clicked "--please select--"
        if(arg3 != 0){
            //get selected content
            String    strName        = my_spinner.getSelectedItem().toString();
            //use hasmap to translate that into a corresponding id. 
            int        intCatID    = hashMuppets.get(strName);
            
            Toast.makeText(getApplicationContext(), String.valueOf(intCatID), Toast.LENGTH_SHORT).show();
        }
    }
    @Override
    public void onNothingSelected(AdapterView<?> arg0) {
        //this is what happens if we select nothing.
        return;
    }
};

As you can see, we ignore the --please select-- and then call the hashmap to get the value.

Easy! Here's the full code:
http://pastebin.com/kVxwEHgm

01 July 2013

Amazon AWS - Signature Version 4


If you decide to try and interact with AWS Glacier API or certain other AWS services you will need to interact with their signature version 4 authentication. Unfortunately in ColdFusion this is one of the hardest things I've ever had to do. Not really ColdFusion's fault, and not really Amazon's fault. Their documentation is comprehensive (although a little confusing) it is just incredibly fiddly. Hashing is a process where a single wrong character completely changes everything. So one slip up causes failures and it can be difficult to determine what you've done wrong.

I have previously blogged about AWS Signiature Version 2 and using it with AWS SES. This article also touches on HMAC and a few of the other key concepts:
http://webdeveloperpadawan.blogspot.co.uk/2012/02/coldfusion-and-amazon-aws-ses-simple.html


AWS Glacier - http://aws.amazon.com/glacier/

AWS Glacier is a very low cost storage solution designed for archiving and backing up data. The basic idea is its cheaper than S3 storage but access is limited. So you don't necessarily have immediate access to your backups. Instead access can be requested and files retrieved within a given time period.
In order to keep costs low, Amazon Glacier is optimized for data that is infrequently accessed and for which retrieval times of several hours are suitable.
- AWS Website
In order to make an API request to Glacier you are required to authenticate each request using their V4 Signature process. Data in Glacier is stored in "Vaults", similar to an S3 bucket a vault is a storage container. For the purposes of this demo I've created a vault using the AWS web management interface. I will be using the API to list all available vaults. In time I hope to expand tutorials and code to cover more complex operations. However, once you've got the signature sorted that shouldn't be too hard.

Code Glorious Code

Again I just want to make the point that I'm just addressing the signature here. I hope to expand the CFC to better deal with making full requests. That will come in time though.

Setup
This should be fairly self explanatory. 
variables.dteNow                  = DateAdd("s", GetTimeZoneInfo().UTCTotalOffset, now());
variables.strPublicKey            = "publickey";
variables.strPrivateKey           = "secretkey";

variables.oAwsSig4                = createObject("component","lib.awsSig4").init(strSecretKey = variables.strPrivateKey);

//We need a few custom date formats
variables.strCanonicalDate        = variables.oAwsSig4.getCanonicalDateFormat(dteNow = variables.dteNow);
variables.strShortDate            = variables.oAwsSig4.getShortDateFormat(dteNow = variables.dteNow);


Step 1 - Create A Canonical Request

The canonical request is basically a standard way to describe the request you are making to AWS. Be that a GET, POST to Glacier or whatever.


This is the aws documentation pseudocode that describes what's happening:

CanonicalRequest =
  HTTPRequestMethod + '\n' +
  CanonicalURI + '\n' +
  CanonicalQueryString + '\n' +
  CanonicalHeaders + '\n' +
  SignedHeaders + '\n' +
  HexEncode(Hash(Payload))

Although I think that's slightly wrong. In my example1 (below), the second empty line is unexplained.

Here's the call I make to the method:

//step 1, create canonical request
strCanonical    = variables.oAwsSig4.createCanonical(
    strHTTPRequestMethod       = "GET",
    strCanonicalURI            = "/-/vaults",
    strCanonicalQueryString    = "",
    arrCanonicalHeaders        = ["date:#variables.strCanonicalDate#","host:glacier.us-east-1.amazonaws.com","x-amz-glacier-version:2012-06-01"],
    arrSignedHeaders           = ["date","host","x-amz-glacier-version"],
    strPayLoad                 = ""
);

You'll note the payload is empty, so the hash at the bottom is simply a SHA-256 hash of "".

The finished Canonical request should look like this.
Example1:
GET
/-/vaults

date:2013-06-26T13:07:03
host:glacier.us-east-1.amazonaws.com
x-amz-glacier-version:2012-06-01

date;host;x-amz-glacier-version
e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855

Step 2 - Create A String To Sign

The string to sign is a little harder to explain out of context. It's basically the message we will hash which will authorize the request to AWS. It's a short and simple string with a very concise format.

The pseudocode is fine here and describes it quite well:
StringToSign  =
Algorithm + '\n' +
RequestDate + '\n' +
CredentialScope + '\n' +
HexEncode(Hash(CanonicalRequest))

Here's my function call:
//Step 2 - Create String To Sign    
strStringToSign    = variables.oAwsSig4.createStringToSign(
    strAlgorithm        = "AWS4-HMAC-SHA256",
    strRequestDate        = variables.oAwsSig4.getStringToSignDateFormat(dteNow = variables.dteNow),
    strCredentialScope    = strShortDate & "/us-east-1/glacier/aws4_request",
    strCanonicalRequest    = strCanonical
);


This is the finished string to sign:
AWS4-HMAC-SHA256
20130626T133038Z
20130626/us-east-1/glacier/aws4_request
6d26f46dbf5d48665e06f44a2f9a65368b3b8d9ef45638b1496fbbe6604ed9db

Step 3a - Calculate Signing Key

OK Now it gets complicated. This is where we start running things through the HMAC function and problems quickly occur. If you do it right though, it'll all come together. AWS do this all in one step, but I think its easier as two.

Here's the documentation pseudocode:

kSecret = Your AWS Secret Access Key
kDate = HMAC("AWS4" + kSecret, Date)
kRegion = HMAC(kDate, Region)
kService = HMAC(kRegion, Service)
kSigning = HMAC(kService, "aws4_request")

Here's my function call:
//create singing key
bSigningKey    = variables.oAwsSig4.createSigningKey(
    dateStamp    = strShortDate,
    regionName    = "us-east-1",
    serviceName    = "glacier"
);

and here's the function:
<cffunction name="createSigningKey" access="public" returnType="binary" output="false" hint="THIS WORKS DO NOT FUCK WITH IT.">
    <cfargument name="dateStamp"    type="string"    required="true" />
    <cfargument name="regionName"    type="string"    required="true" />
    <cfargument name="serviceName"    type="string"    required="true" />
    <cfscript>
        var kSecret     = JavaCast("string","AWS4" & variables.strSecretKey).getBytes("UTF8");
        var kDate       = HMAC_SHA256_bin(arguments.dateStamp, kSecret);
        var kRegion     = HMAC_SHA256_bin(arguments.regionName, kDate);
        var kService    = HMAC_SHA256_bin(arguments.serviceName, kRegion);
        var kSigning    = HMAC_SHA256_bin("aws4_request", kService);
        
        return kSigning;
    </cfscript>
</cffunction>

I know I've not included the function in the other steps, but I want to highlight the importance of two things:
  • kSecret is "AWS4" + Secret Key, then cast into bytes. This is a very important step and where I was going wrong for quite a while.
  • variables.strSecretKey is the secret key you get from AWS in your account section. It's obviously secret and shouldn't be disclosed to anyone. In my example it's set in the variables scope of the cfc.
  • The function I use HMAC_SHA256_bin accepts a binary argument as param1. This is different from the example in my previous blog post on signature version 2, which used two strings as arguments.
So you can see with four HMAC steps, the tiniest mistake means a totally different response. Obviously AWS will be doing the same thing on their end, so if the two don't match, your request won't get approved.

Step 3b - Sign it!

OK Now we bring it all together

signature = HexEncode(HMAC(derived-signing-key, string-to-sign))

We take the signing key from step 3a and the string to sign from step 2:

bSignature    = variables.oAwsSig4.HMAC_SHA256_bin(strStringToSign, bSigningKey);

Step 4 - Put it all together

Now we make our request:
<cfhttp method="GET" url="http://glacier.us-east-1.amazonaws.com/-/vaults">
    <cfhttpparam type="header"         name="Date" value="#variables.strCanonicalDate#">
    <cfhttpparam type="header"        name="x-amz-glacier-version" value="2012-06-01" />
    <cfhttpparam type="header"        name="Authorization" value="AWS4-HMAC-SHA256 Credential=#variables.strPublicKey#/#variables.strShortDate#/us-east-1/glacier/aws4_request,SignedHeaders=date;host;x-amz-glacier-version,Signature=#lcase(binaryEncode(bSignature, 'hex'))#" />
</cfhttp>

  • Note we didn't hex encode our bSigniature from before, so I do that in the value. Probably better done elsewhere, but I'll get to it.
  • Also note the public key. Again this comes from AWS management console.
  • Note the three different dates, one is the strCanonicalDate we created at the top, the other is the short date and finally the hard coded glacier version date.
That's it. That should work!  Obviously you need the cfc. Take a look below for that.


Advice

My advice to anyone attempting to do this in ColdFusion or any other language is as such:
  1. Baby Steps - The documentation is presented in steps. Get each step working perfectly before moving onto the next. They all rely on each other, so a mistake early on will just cascade and waste time later.
  2. Unit Tests - I'm a huge fan of unit tests anyway, but in this case they really helped. Setting up some great unit tests using AWS examples will help you define your input and your output and tweak your code until you get the response you're looking for.
  3. Check Responses - If you actually make a request to AWS they will tell you in the response what the problem is. Plus they'll tell you the expected canonical request and the expected string to sign. These can really help iron out any tiny discrepancies
  4. Try it in Java -  CFML Doesn't have a native HMAC function (pre CF10), and converting too and from byte arrays caused endless problems. So I just did a few piecemeal functions in Java and learned from that.

The CFC

Ah of course one final step. The cfc. As I've said I hope to improve it a great deal and perhaps open source it and put it on cflib. I've also got a bunch of unit tests I wrote which may help people improve it.
Right now I'm just pleased to have got it working and don't want to forget it all so it's going on the blog.


Thanks

I ended up not using the code, but some of Ben Nadel's stuff was really useful to understand. He's written a great cfc that I urge anyone using HMAC in CFML to consider:
http://www.bennadel.com/blog/2412-Crypto-cfc-For-Hmac-SHA1-Hmac-Sha256-and-Hmac-MD5-Code-Generation-In-ColdFusion.htm




<cfcomponent output="false">

<!---
<OWNER> = James Solo
<YEAR> = 2013

In the original BSD license, both occurrences of the phrase "COPYRIGHT HOLDERS AND CONTRIBUTORS" in the disclaimer read "REGENTS AND CONTRIBUTORS".

Here is the license template:

Copyright (c) 2013, James Solo
All rights reserved.

Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:

Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

--->

    <cffunction name="init" access="public" returnType="awsSig4" output="false">
        <cfargument name="strSecretKey" type="string" required="true" />

        <cfset variables.strSecretKey        = arguments.strSecretKey />
        <cfset variables.strPublicKey        = "mypublickey" />
        <cfreturn this>
    </cffunction>


    <cffunction name="createCanonical" access="public" returnType="string" output="false" hint="Create the canonical request">
        <cfargument name="strHTTPRequestMethod"        type="string"    required="true"                 />
        <cfargument name="strCanonicalURI"            type="string"    required="true"                 />
        <cfargument name="strCanonicalQueryString"    type="string"    required="false"    default=""    />
        <cfargument name="arrCanonicalHeaders"         type="array"    required="true"                    />
        <cfargument name="arrSignedHeaders"            type="array"    required="true"                    />
        <cfargument name="strPayload"                type="string"    required="false"    default=""    />
        
        <cfscript>
            var intCount            = 0;
            var strHeaderString        = "";
            var strCanonicalRequest = 
                arguments.strHTTPRequestMethod        & chr(010) &
                arguments.strCanonicalURI            & chr(010) &
                arguments.strCanonicalQueryString    & chr(010);
            
            //Headers
            for(intCount=1; intCount <= arraylen(arrCanonicalHeaders); intCount++){
                strCanonicalRequest    &= arguments.arrCanonicalHeaders[intCount] & chr(010);
            }
            
            strCanonicalRequest    &= chr(010);
            
            //Signed headers
            for(intCount=1; intCount <= arraylen(arrSignedHeaders); intCount++){
                strHeaderString        = arguments.arrSignedHeaders[intCount];
                strCanonicalRequest    &= strHeaderString;
                
                //put a semi-colon between headers, or a new line at end
                if(intCount EQ arraylen(arrSignedHeaders)){
                    strCanonicalRequest    &= chr(010);
                }else{
                    strCanonicalRequest    &= ";";
                }
            }
            
            strCanonicalRequest    &= lcase(hash(arguments.strPayload, "SHA-256"));
            
            return trim(strCanonicalRequest);
        </cfscript>
    </cffunction>


    <cffunction name="createStringToSign" access="public" returnType="string" output="false" hint="I create the string to sign">
        <cfargument name="strAlgorithm"            type="string" required="true" />
        <cfargument name="strRequestDate"        type="string" required="true" />
        <cfargument name="strCredentialScope"    type="string" required="true" />
        <cfargument name="strCanonicalRequest"    type="string" required="true" />
        
        <cfscript>
            var strStringToSign  =
                    arguments.strAlgorithm            & chr(010) &
                    arguments.strRequestDate        & chr(010) &
                    arguments.strCredentialScope    & chr(010) &
                    lcase(hash(arguments.strCanonicalRequest, "SHA-256"));
            
            return strStringToSign;
        </cfscript>
    </cffunction>


    <cffunction name="createSigningKey" access="public" returnType="binary" output="false" hint="THIS WORKS DO NOT FUCK WITH IT.">
        <cfargument name="dateStamp"    type="string"    required="true" />
        <cfargument name="regionName"    type="string"    required="true" />
        <cfargument name="serviceName"    type="string"    required="true" />
        <cfscript>
            var kSecret        = JavaCast("string","AWS4" & variables.strSecretKey).getBytes("UTF8");
            var kDate        = HMAC_SHA256_bin(arguments.dateStamp, kSecret);
            var kRegion        = HMAC_SHA256_bin(arguments.regionName, kDate);
            var kService    = HMAC_SHA256_bin(arguments.serviceName, kRegion);
            var kSigning    = HMAC_SHA256_bin("aws4_request", kService);
            
            return kSigning;
        </cfscript>
    </cffunction>


    <cffunction name="HMAC_SHA256_bin" access="public" returntype="binary" output="false" hint="THIS WORKS DO NOT FUCK WITH IT."> 
        <cfargument name="signMessage"    type="string" required="true" />
        <cfargument name="signKey"        type="binary" required="true" /> 
        
        <cfset var jMsg = JavaCast("string",arguments.signMessage).getBytes("UTF8") /> 
        <cfset var jKey = arguments.signKey />
        
        <cfset var key = createObject("java","javax.crypto.spec.SecretKeySpec") /> 
        <cfset var mac = createObject("java","javax.crypto.Mac") /> 
        
        <cfset key = key.init(jKey,"HmacSHA256") /> 
        
        <cfset mac = mac.getInstance(key.getAlgorithm()) /> 
        <cfset mac.init(key) /> 
        <cfset mac.update(jMsg) /> 
        
        <cfreturn mac.doFinal() />
    </cffunction>


    <cffunction name="toHex" access="public" returnType="string" output="false" hint="I convert binary to hex">
        <cfargument name="bSignature"        type="binary" required="true" /> 
        <cfreturn lcase(binaryEncode(arguments.bSignature, "hex")) />
    </cffunction>
    

    <cffunction name="getCanonicalDateFormat" access="public" returnType="string" output="false" hint="I return a formatted date time for the canonical part of the process">
        <cfargument name="dteNow"    type="date"    required="true" />
        
        <cfreturn "#dateformat(arguments.dteNow, 'yyyy-mm-dd')#T#TimeFormat(arguments.dteNow, 'HH:mm:ss')#" />
    </cffunction>
    

    <cffunction name="getStringToSignDateFormat" access="public" returnType="string" output="false" hint="I return a formatted date time for the string to sign section">
        <cfargument name="dteNow"    type="date"    required="true" />
        
        <cfreturn "#dateformat(arguments.dteNow, 'yyyymmdd')#T#TimeFormat(arguments.dteNow, 'HHmmss')#Z" />
    </cffunction>
    

    <cffunction name="getShortDateFormat" access="public" returnType="string" output="false" hint="I return a short date time">
        <cfargument name="dteNow"    type="date"    required="true" />
        
        <cfreturn "#dateformat(arguments.dteNow, 'yyyymmdd')#" />
    </cffunction>


</cfcomponent>

10 June 2013

CFML REST webservices with Railo

I've been doing a lot of REST web services with CFML and Railo lately and wanted to write up my experiences in case it helps.

First you need to setup Railo with your webservice cfc:
http://www.getrailo.org/index.cfm/whats-up/railo-40-released/features/rest-services/

Second you need to create and configure your cfc:
<cfcomponent rest="true" restpath="/hello">

The restpath provides the step in your URL from which your service is accessed. A normal REST webservice is pretty straightforward. Ensure your method is set to access="remote" and add in httpMethod and a restPath param to the cffunction.
<cffunction name="getmuppets" access="remote" httpmethod="GET" restpath="/getmuppets">

The restpath identifies the url structure you'll use to access the webservice.
The httpmethod tells the webservice if it should respond to GET/POST/PUT etc methods. These methods are defined and talked about more in REST definitions: http://en.wikipedia.org/wiki/Representational_state_transfer#Vocabulary_re-use_vs._its_arbitrary_extension:_HTTP_and_SOAP

Returning data is fairly standard, but if you want to return JSON then you might want to look at my previous blog post.

I've found that unlike much of CFML REST is case sensitive, so its a good idea to make everything lowercase.

This should be enough to get you going, but pretty soon you'll need to add arguments. So lets have a quick look at REST arguments. Lets assume for now we're just interested in a GET request.

You add your cfargument as your normally would, but you also need a param called restArgSource.

<cfargument name="intage"    type="numeric"    restArgSource="Path">

Your new method would look like this:
    <cffunction name="getmuppets" access="remote" produces="application/json" httpmethod="GET" restpath="/getmuppets/intage/{intage}/strsex/{strsex}/">
        <cfargument name="intage"    type="numeric"    restArgSource="Path">
        <cfargument name="strsex"    type="string"    restArgSource="Path">
        
        .....
    </cffunction>

Pay particular attention to how the restpath needs to be updated to match the new arguments. We're using restArgSource set to path, which means your url needs to provide those arguments. Here's an example URL:
http://localhost/rest/demo/hello/getmuppets/intage/30/strsex/male
Each step in the URL is a piece of the puzzle.

There are a few types that restArgSource accepts:
  • Path
  • Query
  • Matrix
  • Cookie / Header
  •  Form
Query is pretty straightforward, instead of using path (as above) you can just get your arguments from the query scope, i.e. ?strage=30. Form is when an argument comes from the FORM scope and you'd normally only use this for post and put httpMethods.
For a full explanation of these types, this article provides a good explanation:
http://www.adobe.com/devnet/coldfusion/articles/restful-web-services.html

That's it, you should be ready to write your own. Best of luck!







30 May 2013

Railo Rest JSON Web Service


So I've been writing lots of REST web services lately with Railo 4.0 and noticed a strange issue / feature when returning json.

So I write me a nice little function and I think everything will work with a little CFML magic:

    <cffunction name="getmuppets" access="remote" returntype="string" httpmethod="GET" restpath="/getmuppets">
        <cfscript>
            var arrMuppets    = [
                {name = "kermit", age = 20},
                {name = "fuzzy", age = 30},
                {name = "animal", age = 40}
            ];
            
            return serializeJson(arrMuppets)
        </cfscript>
    </cffunction>


All good? No :( The json is fine when you call the function locally, but when you call it as a rest webservice all the double quotes get escaped. Which renders it invalid json and is not much use for anything.
"[{\"age\":20,\"name\":\"kermit\"},{\"age\":30,\"name\":\"fuzzy\"},{\"age\":40,\"name\":\"animal\"}]"


So I eventually figured out you've got to change the headers and content returned by the function.
    <cffunction name="getmuppets" access="remote" produces="application/json" httpmethod="GET" restpath="/getmuppets">
        <cfscript>
            var arrMuppets    = [
                {name = "kermit", age = 20},
                {name = "fuzzy", age = 30},
                {name = "animal", age = 40}
            ];
            
            response    = {
                status        = 200,
                headers        = {},
                content        = serializeJson(arrMuppets)
            };
        
            restSetResponse(response);
        </cfscript>
    </cffunction>

Once you do all that, you get valid json:


[{"age":20,"name":"kermit"},{"age":30,"name":"fuzzy"},{"age":40,"name":"animal"}]

18 May 2013

Node JS

For no particular reason I thought I'd have a stab at Node.js today. I'm a bit curious and keen to see what all the fuss is about. Much (I suspect) like a lot of web devs out there I'm good at JS and jQuery (I even dabbled in prototype and YUI) but would've call myself a JavaScript pro! Today I just wanted to get a Hello World out the door and then later try and find out a bit more and perhaps get more advanced.

Install
So I must have read a dozen different tutorials today and every one of them is different. The official note.js site has an instillation guide https://github.com/joyent/node/wiki/Installation but I found it a bit daunting, so I pieced a few together.

I'm on Ubuntu so I downloaded the node-v0.10.7.tar.gz file from http://nodejs.org/ and unpacked it to a new directory.

Then I opened up a console and simply typed:

sudo make install

This took a while as Ubuntu busied itself, but that was it, pretty simple.
You can verify everything is running by typing

node --version

Get Started

Then I created a directory under /var/www/ and the obligatory Hello World file:

console.log("Hello World - All your base belong to me");

Then, still in the console I moved to my new application directory and executed my file:

node helloworld.js

That was it! Easy as pie so far!

14 May 2013

Android Fragments

In Android a fragment is a "behaviour or a portion of user interface in an Activity". I first met fragments when putting maps in my Android activity. They're also useful for putting various UI components on one activity.
I've adapted this example from here http://developer.android.com/training/basics/fragments/index.html
Here's the simple breakdown of using a list fragment:

1) Create an activity_main.xml in res/layout/ as such:
<?xml version="1.0" encoding="utf-8"?>

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="horizontal"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <fragment android:name="com.example.droidtestnew.smallpage"
              android:id="@+id/article_fragment"
              android:layout_weight="2"
              android:layout_width="0dp"
              android:layout_height="match_parent" />

</LinearLayout>
2) Create another activity_main.xml in res/layout-large/ (note the second fragment):
<?xml version="1.0" encoding="utf-8"?>

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="horizontal"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <fragment android:name="com.example.droidtestnew.smallpage"
              android:id="@+id/headlines_fragment"
              android:layout_weight="1"
              android:layout_width="0dp"
              android:layout_height="match_parent" />

    <fragment android:name="com.example.droidtestnew.smallpage"
              android:id="@+id/article_fragment"
              android:layout_weight="2"
              android:layout_width="0dp"
              android:layout_height="match_parent" />

</LinearLayout>
3) Create a java class called smallpage.java
package com.example.droidtestnew;

import android.os.Build;
import android.os.Bundle;
import android.support.v4.app.ListFragment;
import android.widget.ArrayAdapter;

public class smallpage extends ListFragment {

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        String arrHello[] = {
            "Hello One",
            "Goodbye Two"
        };
        
        // We need to use a different list item layout for devices older than Honeycomb
        int layout = Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB ?
                android.R.layout.simple_list_item_activated_1 : android.R.layout.simple_list_item_1;

        // Create an array adapter for the list view, using the Ipsum headlines array
        setListAdapter(new ArrayAdapter<String>(getActivity(), layout, arrHello));
    }

}
4) Change MainActivity.java to extend FragmentActivity:
public class MainActivity extends FragmentActivity {
You're done. That should be all you need. If you launch this on a small screen, you'll see the one fragment list, if you launch it on a tablet, you'll see two lists.

Easy as pie! Obviously this is an incredibly basic example, but it should get you started with fragments.

28 April 2013

Building a CF SOAP Webservice


I recently needed to create a web service which pleased me as its very easy with coldFusion.


Although, that said, one thing that has often puzzled me is the Application.cfc and the cfc initialization. You probably wouldn’t want to use your normal Application.cfc as it’s likely a bit excessive. To my mind webservice requests could take place weeks apart, or just minutes and should be lightening fast, so a very lightweight initialization process would be ideal.

Lets assume a very basic webservice.cfc:


<cfcomponent output="false">
    
    <cffunction name="getUsers" access="remote" returnType="query" output="false" hint="I get some users">
        <cfreturn application.oUsers.getUsers() />
    </cffunction>
    
</cfcomponent>

So oUsers is our DAO or Business object which we use in our application. Normally it would be passed in with an init method, but with a webservice we don’t have the same concept of init’ing objects. So how does one go about initializing our DAO? In the past I’ve seen many takes on this. I’ve seen:

In the method:
<cffunction ...>
    <cfset var oUsers = createObject(...)>
    <cfreturn var oUsers.getUsers()>

In the actual webservice.cfc, scoping it this/variables/application
<cfcomponent output="false">
    <cfset variables.oUsers = createObject(...)>
    <cffunction ...


Both of the above involve the dao cfc being re-created on every web-service request. Not exactly ideal in terms of performance.

So I think the best idea I’ve seen so far is create an application.cfc like so:


<cfcomponent output="false">
    <cfset this.strDsn            = "mydsn" />
    
    <cffunction name="onApplicationStart" access="public" returnType="boolean" output="false">
        <cfset application.oUsers    = createObject("component","usersDao").init(strDsn    = this.strDsn) />
        <cfreturn true />
    </cffunction>
    
</cfcomponent>


This gives a lightweight application scope in which we can initialize our object and then call throughout our webservices! Excellent!

If you’ve got any suggestions on how to improve this, please feel free to comment.