the litl developer blog
14Dec/100

Understanding Accelerometer Development

by @ryancanulla

What is an Accelerometer?
An accelerometer is a piece of hardware that measures the acceleration of forces. There are two types of forces that we care about; static and dynamic. You can think of static force as gravity which at all times is pulling us towards the center of the earth. We use static acceleration to figure out the angle an object is tilted. Dynamic acceleration is used for measuring the actual motion of an object. For this intro we’ll be talking mostly about tilt-based static acceleration.


Common uses

There are accelerometers all around us from our cars to our computers and phones. In cars they use accelerometer data to determine vibrations on the engine and in the airbag sensors. Companies also use accelerometers in hard-drives to protect data during collisions and general impact. Nintendo Wii shaped the future of motion gaming adding an accelerometer to their remote. Whenever you see a labyrinth style game or are playing a driving game by tilting your phone or tablet you can thank the accelerometer. As developers it’s our job to learn and interpret this information in order to improve the experience to our users.


How to handle local accelerometer on mobile device
When you are writing flash application that will handle local accelerometer updates from a phone or tablet the work flow is very simple. You check the to see if the device supports accelerometer using the flash.sensors.Accelerometer.isSupported() method. If it is supported you register a few event listeners, then handle the updates when they come in.

if (Accelerometer.isSupported) {
		accelerometer = new Accelerometer();
		accelerometer.addEventListener(AccelerometerEvent.UPDATE, accUpdateHandler);
}

private final function accUpdateHandler(event:AccelerometerEvent):void {
	xSpeed -= event.accelerationX;
	ySpeed += event.accelerationY;
}


How to handle accelerometer data from litl os remotes

When you are dealing with multiple remotes connected to a single application things get a bit more complicated because you need to pair remote updates with specific remotes, manage connections, and not mix it up in the meantime. This is an approach that works for us. It involves the creation of three classes by the developer.


LitlRemoteManager()

We will need to extend RemoteHandlerManager in order to inherit functionality. By doing this now we can override two important methods; onRemoteConnected and onRemoteDisconnected. You can do whatever you want inside these methods knowing that they’ll be called when a remote connects/disconnects.

You will need to instantiate after you are connected to the LitlService() as you will need to pass a reference to your service into it’s constructor. You will also need to instantiate a new RemoteFactory() in the constructor. This is what it looks like in our instantiation:

private function createRemoteManager():void {
	remoteManager = new LitlRemoteManager(_service, new RemoteFactory());
}


RemoteFactory()

Implement IRemoteFactory(), return RemoteHandler() and you are all set. I usually set this up once and barely look at it again. :-)

package service
{
    import com.litl.helpers.richinput.remotehandler.IRemoteHandler;
    import com.litl.helpers.richinput.remotehandler.IRemoteHandlerFactory;

    public class RemoteFactory implements IRemoteHandlerFactory
    {
        public function RemoteFactory() {
        }

        public function createHandler():IRemoteHandler {
            return new RemoteHandler();
        }

        public function get klass():Class {
            return RemoteHandler;
        }
    }
}


RemoteHandler()

We have one job left to do and RemoteHandler() keeps it simple and to the point. This is where we define what to do when we get accelerometer updates. Start by extending AccelerometerEventHandler() and implement IRemoteHandler(). Next, override onAccelerometerEvent and handle your logic to handle accelerometer data. I usually loop through an array of remotes/players in my model and reference the remoteID property to match up remotes.

package service
{
    import com.litl.helpers.richinput.remotehandler.AccelerometerRemoteHandler;
    import com.litl.helpers.richinput.remotehandler.IRemoteHandler;
    import com.litl.sdk.event.AccelerometerEvent;

    public class RemoteHandler extends AccelerometerRemoteHandler implements IRemoteHandler
    {
	public var xSpeed:Number = 0;
	public var ySpeed:Number = 0;

        public function RemoteHandler() {
            super();
        }

        override protected function onAccelerometerEvent(event:AccelerometerEvent):void {
	    xSpeed -= event.accelerationX;
    	    ySpeed += event.accelerationY;
        }
    }
}


Wrapping up

As you can see there are not too many differences between the two workflows. Check back soon as we'll be posting more advanced accelerometer development articles, tutorials, tips and tricks!

15Sep/100

Managing Channel Properties on the litl OS

by @ryancanulla

What are channel properties?

Channel properties allow the developer to take application data and put it in local system storage. This memory is limited, but can be very useful for channel configurations, user preferences, high scores, or something else that’s needed by your channel.

There are four types of channel properties. Each property type has a specific set of permissions. Permissions range from device specific to properties that are shared amongst different accounts/households/devices.

Below is a list of the litl OS channel properties:

  • Global: generally read-only and tell the channel about the device/environment which they are running on
  • Account: these properties will be included on all instances of your channel for one household account
  • Device: properties that are only visible to one specific channel and only on the device it is installed/running on
  • Shared: properties that are shared with any account/household that your channel is shared with

Storing properties locally

To store properties on your device simply set them on your LitlService instance; in this example that would be the service variable. Keep in mind that channel properties should be name value pairs.

Example:

service.addEventListener(PropertyMessage.PROPERTY_CHANGED, onPropertiesChanged);

Example:

service.sharedProperties.myProp = "some value";     service.accountProperties.anotherProp = "another value";     service.deviceProperties.thirdProp = "yet another";

Retrieving local properties from your channel

Listen for the “PROPERTY_CHANGED” event on your LitlService instance. Once you do that you will have everything you need inside of the event handler message.

In the event handler you will look for an Array of properties (e.parameters). Once you have that you can loop though this array to a) check for specific property names (ie. “Prop1”, “madeUpProperty”, or “zipCode”) or b) check what type of property type you are dealing with (ie. DEVICE, SHARED, ACCOUNT, or GLOBAL).

Example:

private function onPropertiesChanged(e:PropertyMessage):void {
	var properties:Array = e.parameters;
		for(var i:uint=0; i < properties.length; i++) {
			if(properties[i].name == "zipCode" && e.propertyScope == PropertyScope.GLOBAL){
				zipLabel.text = properties[i].value;
			}
		}
}

Note that it is important to match the properties that you are looking for with the property type that you expext it should be paired to.

if(properties[i].name == "username" && e.propertyScope == PropertyScope.DEVICE){

You can find a great example of working with channel properties in the ZipCode tutorial on the Sample Channels page:

http://developer.litl.com/create/sample_channels.htm

Tagged as: , , No Comments
8Sep/100

Creating Custom Item Renderers for Litl Controls

by @ryancanulla

As you know, the litl SDK come with some pretty handy controls that will assist in your development process by allowing you to focus on the task at hand, and not re-inventing the controls (I mean wheel). In this post, we’ll be discussing how you can create custom item renderers for use with controls like the SlideShow and FilmStrip. Both of these will take an array and scroll through the data. We’ll look at how we can customize that data to create unique views for your channel.

You can find the completed code for this tutorial at developer.litl.com under sample channels.

Create a Value Object

This value object will allow us to type our data to a specific object. Ours looks something like this.

package com.litl.itemrenderersample.vo
{

    public class RendererDataObjectVO
    {
        public var title:String;
        public var description:String;
        public var address:String;
        public var imageUrl:String;
    }
}

Create an itemRenderer class

This class will define what data will be presented to the user via our control, how it looks, where it is placed, and how it’s updated. You can name it whatever you like, and store it somewhere in your channel directory (I usually store it inside of a renderers directory).

This class must do two things:

  • Extend ControlBase
  • Implement IitemRenderer
package com.litl.itemrenderersample.renderers
{
    import com.litl.control.ControlBase;
    import com.litl.control.listclasses.IItemRenderer;

    public class RestaurantItemRenderer extends ControlBase implements IItemRenderer
    {
        public function RestaurantItemRenderer() {
            super();
        }

    }
}

Override the createChildren() method

This is where you create the objects for your custom item renderer. These objects should have some sort of data property that will change with each object in your renderers collection. Great examples of these items are TextFields, TextAreas, and Images.

        override protected function createChildren():void {
            mouseChildren = false;

            background = new Sprite();
            addChild(background);

            title = new TextField();
            format = new TextFormat("CorpoS", 36, 0xffffff, false);
            format.align = TextFormatAlign.LEFT;
            title.defaultTextFormat = format;
            title.wordWrap = true;
            title.multiline = true;
            title.selectable = false;
            title.antiAliasType = "advanced";
            title.gridFitType = "pixel";
            title.autoSize = TextFieldAutoSize.CENTER;
            addChild(title);

            description = new TextField();
            var descriptionFormat:TextFormat = new TextFormat("CorpoS", 28, 0xffffff, false);
            description.defaultTextFormat = descriptionFormat;
            description.wordWrap = true;
            description.multiline = true;
            description.selectable = false;
            description.antiAliasType = "advanced";
            description.gridFitType = "pixels";
            description.autoSize = TextFieldAutoSize.CENTER;
            addChild(description);

            address = new TextField();
            address.defaultTextFormat = descriptionFormat;
            address.wordWrap = true;
            address.multiline = true;
            address.selectable = false;
            address.antiAliasType = "advanced";
            address.gridFitType = "pixels";
            address.autoSize = TextFieldAutoSize.CENTER;
            addChild(address);

            loader = new Loader();
            loader.contentLoaderInfo.addEventListener(Event.COMPLETE, onImageComplete, false, 0, true);
            addChild(loader);
        }

Override the updateProperties() method

This is where you will change the data that is presented to the user for all of your renderers child objects. For example, this is where we set/update the text property for a TextField or where we load a new image based on a new URL.

        override protected function updateProperties():void {
            if (title != null)
                title.text = (_data == null) ? "" : _data.title;
            description.text = (_data == null) ? "" : _data.description;
            address.text = (_data == null) ? "" : _data.address;

            if (loader != null) {
                loader.load(new URLRequest(_data.imageUrl));
            }
        }

Override the layout() method

This is where we position our objects on the stage. We check the _width && _height properties that we inherit from ControlBase.

        override protected function layout():void {
            if (_width > 0 && _height > 0) {
                graphics.clear();
                graphics.beginFill(0x0, 1);
                graphics.lineStyle(1, 0xffffff, 1, true);
                graphics.drawRect(0, 0, _width, _height);
                graphics.endFill();

                loader.x = 30;
                loader.y = 30;

                title.width = _width - 100;
                title.y = loader.y + loader.height + 25;
                title.x = 30;

                description.width = _width - 10;
                description.y = title.y + title.height;
                description.x = 30;

                address.width = _width - 100;
                address.y = _height - 40;
                address.x = 30;
            }
        }

Create the _data variable

This private variable will be typed to your value object that we created earlier.

private var _data:RendererDataObjectVO;

Create getters/setters for your _data property

Create these however you want, but I like to right click on my _data var → Source → Create Getters/Setters.

The thing to note here is that we accept an Object in the set data method and type it to our Value Object.

        public function get data():Object {
            return _data;
        }

        public function set data(obj:Object):void {
            var vo:RendererDataObjectVO = obj as RendererDataObjectVO;
            _data = vo;
            invalidateProperties();
        }

Create various setters

These getters/setters are really just a formality at this point. Any modification would be beyond the scope of this simple tutorial.

What needs to be created:

  • set enabled(b:Boolean):void
  • set selected(b:Boolean):void
  • get selected():Boolean
  • get isReady():Boolean
        public function set enabled(b:Boolean):void {
        }

        public function set selected(b:Boolean):void {
        }

        public function get selected():Boolean {
            return false;
        }

        public function get isReady():Boolean {
            return (loader.contentLoaderInfo.bytesLoaded == loader.contentLoaderInfo.bytesTotal);
        }

Create the SlideShow and set the item renderer property to your new custom item renderer

This is the last step. Now you can create additional item renderer classes and change them at runtime! Try it out, have fun, and be sure to let us know if you have any questions!

            slideshow = new Slideshow();
            addChild(slideshow);

            slideshow.itemRenderer = RestaurantItemRenderer;

            slideshow.setSize(800, 600);

            var item1:RendererDataObjectVO = new RendererDataObjectVO();
            item1.title = "Thaitation";
            item1.address = "39 Jersey St. Boston, MA";
            item1.description = "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nullam at elit quis ligula tristique vulputate. Donec tempor imperdiet urna quis pellentesque. Phasellus eu arcu at tortor ultricies porta vel sed leo. Aenean tincidunt auctor risus, sit amet tempor lectus hendrerit id. Pellentesque dui nulla, vulputate nec egestas nec, porttitor non lectus.";
            item1.imageUrl = "assets/thaitation.jpg";

            var item2:RendererDataObjectVO = new RendererDataObjectVO();
            item2.title = "Sonsie";
            item2.address = "255 Newbury St. Boston, MA";
            item2.description = "Sed leo enim, gravida vitae consequat quis, venenatis nec urna. Pellentesque erat lacus, posuere sit amet scelerisque eget, imperdiet quis tortor. Phasellus in purus eget urna imperdiet ullamcorper. Etiam mattis, libero ac interdum venenatis, est eros elementum ligula, euismod tincidunt nisl lorem id lacus.";
            item2.imageUrl = "assets/sonsie.jpg";

            slideshow.dataProvider = [ item1, item2 ];

Completed item renderer:

19Aug/100

Getting a user’s Location from a Channel

by @ryancanulla

Geo-location is a hot feature, especially in the world of mobile apps. While our devices don't travel as much, there are still limitless possibilities when basing an app around a user's location.

The litl Channel SDK gives you access to a device user's zip code by way of two things: User properties and the Location capability. The latter is a privacy hook that, when accessed, notifies the user that this channel is accessing private information. We've put together a ready-to-run sample channel that shows you how to obtain the "zip code":

1. Download the "zip-code-sample-channel"
You can download the project archive from the sample channels section of http://developer.litl.com. This sample channel was created using Flash Builder as an ActionScript Project.

2. Import the project into Flash Builder.

3. Link the project to your as3-sdk-core library project.
Right Click on "zip-code-sample-channel">Properties>ActionScript Build Path>Add Project.

4. Open the simulator.

5. Grant the location capability to your channel in the simulator.

6. Run the channel.

What's going on here.
Basically we just listen for a PropertyMessage.PROPERTY_CHANGED event on our service and then pull the zip code from that event handler.

 service.addEventListener(PropertyMessage.PROPERTY_CHANGED, onPropertiesChanged);

Inside of the handler we loop through an array of properties and check to find one called "zipCode". Once we find the zip code we then make sure that it's a global property. If both tests pass then we have the zip code available to us in two places. First, we can pull it from the array itself "properties[i].value". The second option available to use is to pull it directly from our service via the "service.zipCode" property.

		private function onPropertiesChanged(e:PropertyMessage):void {
			var properties:Array = e.parameters;

			for(var i:uint=0; i < properties.length; i++) {
				if(properties[i].name == "zipCode" && e.propertyScope == PropertyScope.GLOBAL){
					zipLabel.text = properties[i].value;

					/**
					 * an also be set like this
					 * zipLabel.text = service.zipCode;
					 *
					 */
				}
			}
		}

Here's the working code!

package {
	import com.litl.sdk.enum.PropertyScope;
	import com.litl.sdk.message.PropertyMessage;
	import com.litl.sdk.service.LitlService;

	import flash.display.Sprite;
	import flash.text.TextField;

	public class Main extends Sprite {

		private var service:LitlService;
		private var zipLabel:TextField;

		public function Main() {
			service = new LitlService(this);
			service.addEventListener(PropertyMessage.PROPERTY_CHANGED, onPropertiesChanged);
			service.connect("channel_id", "Zip Code Sample Channel", "v1.01");

			createZipLabel();
		}

		private function onPropertiesChanged(e:PropertyMessage):void {
			var properties:Array = e.parameters;

			for(var i:uint=0; i < properties.length; i++) {
				if(properties[i].name == "zipCode" && e.propertyScope == PropertyScope.GLOBAL){
					zipLabel.text = properties[i].value;

					/**
					 * an also be set like this
					 * zipLabel.text = service.zipCode;
					 *
					 */
				}
			}
		}

		private function createZipLabel():void {
			zipLabel = new TextField();
			zipLabel.x = 50;
			zipLabel.y = 50;
			addChild(zipLabel);
		}
	}
}

This example also demonstrates how you would work with either ACCOUNT, DEVICE, GLOBAL, or SHARED properties. For additional support, please check our forums or contact us.

5Aug/100

New sample channels added to developer.litl.com!!

by @ryancanulla

We've added two additional sample channels to help get developers started with the SDK!

The first is a sample channel that makes use of the web card capability. This capability allows users to open new web cards from within their channel. Let's say I have a news channel and I'd like to send users to the actual article out on the web; this channel will show you how!

The second channel that we added is a starter flickr channel. You'll need to get your own API Key + secret to use this one. Besides giving you an out of the box templet to get started with, we're also showing you how to use the filmstrip control and override its ImageRenderer! In addition, we also show you how to keep your litl service information inside of the application controller (I like it there).

http://developer.litl.com/create/sample_channels.htm

Let us know what you think or if you have other ideas/requests for sample channels!