Android’s Fragmentation: Split Personality Disorder
There has been a lot of talk about fragmentation in the Android ecosystem. Anyone who says it’s not fragmented has to be kidding themselves. If an iOS user sees a cool app on another person’s iOS device, they know that it is available to them as well. Unfortunately, the same is not true for Android users. When I create an Android application, I try to run it on as many devices as possible prior to release. The tweaks to the OS made by device manufacturers can (and do) affect application performance and stability. One can easily observe this by looking at reviews in the Apps Market where users describe applications force-closing randomly on specific phones.
One of the greatest benefits of Android is that it gives customers the ability to chose a device with a UI and hardware most appealing to them. This is also its greatest curse since it causes fragmentation in the Android ecosystem, a problem much more difficult for Google than it is for Apple and BlackBerry because Google doesn’t control the hardware. The Android Update Alliance was created to guide device-makers and carriers towards updating their customers more quickly, but so far it seems dead in the water. The small tweaks that carriers make to the OS help their devices stand apart, not just from other operating systems but other Android phones as well. These differences make updating them much more difficult since the device makers need to ensure that every aspect of their customized version works on the latest update. On top of that, the hardware-makers don’t see another dime from goods and services sold within the Android ecosystem, so there is little incentive for carriers to keep older phones up to date. (Although I know I would have brand loyalty and be much more likely to continue buying a specific line of devices if the carrier guaranteed me the latest updates every time, but that’s a topic for a different post entirely.)
To make matters worse, two of the worlds most popular Android-based tablets are built on top of extremely dated versions of the OS. Amazon’s Kindle Fire and Barnes and Noble’s Nook Tablet are both running customized versions of Android 2.3. This forces developers to ask very difficult questions: “do we lower the features of our applications and potential quality to make one app that will run on all tablets, create two applications or ignore devices with older versions of the OS?” These are questions that iOS developers generally don’t need to ask themselves, thanks to Apple’s strict control over the hardware. For a visual reference of just how much variation there is in Android versions out there, check out Michael Degusta’s chart, linked at the bottom of this post.
The bottom line is that Google needs to apply more pressure to carriers and device-makers to keep their customized versions in sync with the latest version of Android. When a customer goes into the store, they should be able to look at a phones capabilities, hardware and customized UI without having to worry about whether or not their favorite apps will work on the device due to tweaked or outdated Android software. It’s an incredible benefit to iOS users that Apple keeps much of its older hardware on the latest version of the OS, and I believe that’s one of the huge appeals of Apple’s ecosystem. Google needs to give its user base that same assurance.
It’s my stance that phones should get the latest version of Android within two months of its release, and continue to receive updates for at least 2 years (This works in the USA where customers are typically offered a discounted phone upgrades at the end of a 2 year contract. I’m not sure if this would be a good solution for customers outside the USA). Tablets should get updates for at least 4 years from their release. I realize that is forever in technology, but tablets are more expensive and beginning to replace laptops. If I were a student who opted for a tablet over a laptop, I’d like to believe it will function fully for me through my college career.
My final thought – When a carrier no longer wants to provide updates to its customized versions, then they should open up their boot-loaders to allow the developer community to keep a device alive and up-to-date. This will help give Android phones that are no longer in service contracts a second life as MP3 players, development devices and iPod touch equivalents.
- Android Orphans: Visualizing a Sad History of Support | October 26, 2011
No CommentsA Better Way to Skin the TabNavigator in Flex 3.5
… is to not use TabNavigator at all. Use a ViewStack and RadioButtons in an HBox!
I like doing skinning work in Flex but there certainly are a few components that I often times find easier to just re-engineer than skin. Scroll bars and TabNavigators are some examples of such components. I’ve heard skinning these components has gotten much easier in Flex 4, but alas, all my projects are still being developed in Flex 3.5.
I was recently given the task of skinning a ‘tabbed’ component, which was previously using the TabNavigator. In Flex 3.5, one can assign custom skins for the first, and last tabs, then a repeating skin for any in-between. This is a fairly common setup for tabs, but unfortunately in this particular component each tab needed to be unique. Another caveat of the component was that the tab bar needed to be wider than the views. After struggling once again to skin the TabNavigator to meet my needs, I finally decided that it might be easier to just do a little re-engineering.
In the past I’d done a series of normal Buttons in an HBox and scripted the ‘turn off/on’ for the other buttons. This time I decided to use RadioButtons and it went flawlessly! The script below shows how to do this. I believe this approach could be used in many situations and not require a lot of re-engineering since it can be done entirely in MXML. Another neat feature of this that the TabNavigator doesn’t allow is a ‘intro screen’ that doesn’t necessarily relate to the tabs, like the blank grey view in my example below.
<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
layout="absolute"
width="500" height="300">
<mx:RadioButtonGroup id="fakeTabGroup" />
<mx:HBox id="radioButtons" width="100%" height="100" horizontalGap="0">
<mx:RadioButton styleName="tab1"
group="{fakeTabGroup}" value="1"/>
<mx:RadioButton styleName="tab2"
group="{fakeTabGroup}" value="2"/>
<mx:RadioButton styleName="tab3"
group="{fakeTabGroup}" value="3"/>
</mx:HBox>
<mx:ViewStack id="views"
x="0" y="100"
selectedIndex="{ (fakeTabGroup.selectedValue as Number) }"
width="100%" height="200" >
<mx:Canvas backgroundAlpha="1" backgroundColor="0x666666" />
<mx:Canvas backgroundAlpha="1" backgroundColor="0x000000" >
<mx:Label horizontalCenter="0" verticalCenter="0" text="BATMAN!" styleName="characterName" />
</mx:Canvas>
<mx:Canvas backgroundAlpha="1" backgroundColor="0x000000" >
<mx:Label horizontalCenter="0" verticalCenter="0" text="WOLVERINE!" styleName="characterName" />
</mx:Canvas>
<mx:Canvas backgroundAlpha="1" backgroundColor="0x000000" >
<mx:Label horizontalCenter="0" verticalCenter="0" text="WONDERWOMAN!" styleName="characterName" />
</mx:Canvas>
</mx:ViewStack>
<mx:Style>
.characterName {
fontSize: 24;
fontWeight: bold;
color: #FFFFFF;
}
.tab1 {
up-skin: Embed(source='/style/batman_d.jpg');
down-skin: Embed(source='/style/batman_u.jpg');
over-skin: Embed(source='/style/batman_u.jpg');
selected-up-skin: Embed(source='/style/batman_u.jpg');
selected-down-skin: Embed(source='/style/batman_u.jpg');
selected-over-skin: Embed(source='/style/batman_u.jpg');
upIcon: ClassReference("mx.skins.ProgrammaticSkin");
overIcon: ClassReference("mx.skins.ProgrammaticSkin");
downIcon: ClassReference("mx.skins.ProgrammaticSkin");
selectedUpIcon: ClassReference("mx.skins.ProgrammaticSkin");
selectedOverIcon: ClassReference("mx.skins.ProgrammaticSkin");
selectedDownIcon: ClassReference("mx.skins.ProgrammaticSkin");
disabledIcon:ClassReference("mx.skins.ProgrammaticSkin");
selectedDisabledIcon: ClassReference("mx.skins.ProgrammaticSkin");
}
.tab2 {
up-skin: Embed(source='/style/wolverine_d.jpg');
down-skin: Embed(source='/style/wolverine_u.jpg');
over-skin: Embed(source='/style/wolverine_u.jpg');
selected-up-skin: Embed(source='/style/wolverine_u.jpg');
selected-down-skin: Embed(source='/style/wolverine_u.jpg');
selected-over-skin: Embed(source='/style/wolverine_u.jpg');
upIcon: ClassReference("mx.skins.ProgrammaticSkin");
overIcon: ClassReference("mx.skins.ProgrammaticSkin");
downIcon: ClassReference("mx.skins.ProgrammaticSkin");
selectedUpIcon: ClassReference("mx.skins.ProgrammaticSkin");
selectedOverIcon: ClassReference("mx.skins.ProgrammaticSkin");
selectedDownIcon: ClassReference("mx.skins.ProgrammaticSkin");
disabledIcon:ClassReference("mx.skins.ProgrammaticSkin");
selectedDisabledIcon: ClassReference("mx.skins.ProgrammaticSkin");
}
.tab3 {
up-skin: Embed(source='/style/wonderwoman_d.jpg');
down-skin: Embed(source='/style/wonderwoman_u.jpg');
over-skin: Embed(source='/style/wonderwoman_u.jpg');
selected-up-skin: Embed(source='/style/wonderwoman_u.jpg');
selected-down-skin: Embed(source='/style/wonderwoman_u.jpg');
selected-over-skin: Embed(source='/style/wonderwoman_u.jpg');
upIcon: ClassReference("mx.skins.ProgrammaticSkin");
overIcon: ClassReference("mx.skins.ProgrammaticSkin");
downIcon: ClassReference("mx.skins.ProgrammaticSkin");
selectedUpIcon: ClassReference("mx.skins.ProgrammaticSkin");
selectedOverIcon: ClassReference("mx.skins.ProgrammaticSkin");
selectedDownIcon: ClassReference("mx.skins.ProgrammaticSkin");
disabledIcon:ClassReference("mx.skins.ProgrammaticSkin");
selectedDisabledIcon: ClassReference("mx.skins.ProgrammaticSkin");
}
</mx:Style>
</mx:Application>
One Comment
Creating Objects in JavaScript Part 1
Going from writing ActionScript 3 (AS3) and Flex applications to HTML5/JavaScript is like stepping into a time machine! JavaScript (JS), while a very powerful language, lacks many of the object oriented (OO) programming features that have become standards of most modern languages. Things like strongly typed variables, multiple inheritance and clearly defined scopes are not available in JS. All of these nuances can make going from AS3 to JS… unpleasant. Have no fear though, over the next few blog posts I plan to discover and explain how to overcome these obstacles and better understand HTML5. I’m learning this myself, so bear with me and feel free to leave comments if something isn’t clear or is inaccurate. Sharing is caring.
Alright, so here we go. Lets start out just discussing some of the primitive objects that are built into AS3 and what their JS counterpart is.
| ActionScript3 Data Types | JavaScript Equivalent |
1. Object 2. Number | int | unit 3. String 4. Boolean 5. Array 6. Dictionary 7. Array 8. Date 9. Function 10. Class 11. Prototype 12. Getter / Setter |
1. Object 2. Number 3. String 4. Boolean 5. Object 6. Object 7. Array (Object) 8. Date 9. Function 10. Function 11. Prototype 12. Function |
Notice how many of those primitives are simply of type Object? That’s because everything except for those few primitives such as String, Number, Boolean, Array, and Date are either Objects or Functions. What about Prototype? Well that’s a special case I will discuss in more detail in a later post. (Note that just because JS and AS3 both have a ‘Date’ or a ‘String’ object, does not mean that they will have the same properties and functions.)
So how do we create our own objects in in JavaScript? One of the simplest ways is to declare them inline with code. This will give you an object that can be used in the global space or within functions, but doesn’t offer anything in the realm of reusability. Here’s an example where we create a new object with its own properties and a single function:
var artist = {
hunger: ‘starving’,
hands: ‘covered in paint’,
drink: function (){
return ‘Drinking lots of whiskey’}
}
As you can see, the functions and the properties we’ve declare within the var artist are available. But what would happen if we later put artist.drink = function { return ‘Drinking lots of milk’ }? The function would return ‘Drinking lots of milk!’, and lets face it, artists want scotch whiskey! So lets figure out how to make our artist object both reusable, and attempt to privatize some of those variables and functions. Observe our new Artist:
{code type=javascript}
function Artist( name, medium ) {
var name = name;
var hunger = 1; //
this.medium = medium;
this.getName = function() {
return name;
}
this. makeArt = function() {
hunger–;
}
this.feed = function( amount ) {
hunger += amount;
}
this.getHunger = function() {
return hunger;
}
}
// SCENARIO A
var a = new Artist( ‘DC’, ‘Oil Paint’);
alert( ‘Name: ‘ + a.name ) // Name: undefined
alert( ‘Name: ‘ + a.getName() ) // Name: DC
a.name = ‘I broke it.’
alert( ‘Name: ‘ + a.name ) // Name: I broke it
alert( ‘Name: ‘ + a.getName() ) // Name: DC
// SCENARIO B
a.feed( 5 );
alert( a.hunger ); // undefined
alert( a.getHunger() ) // 6
// SCENARIO C
alert( a.medium ); // Oil Paint
a.medium = ‘Clay’;
alert( a.medium ); // clay
// SCENARIO D
a.getHunger = function(){ return ‘aw crap, a developer can still break me!’ };
alert( a.getHunger() ) // aw crap, a developer can still break me!
{/code}
So we have a constructor function for Arist, that takes two parameters, a name and a medium. The name we put int to a basic ‘var name’ statement, which means that it will be accessible to everything within the function, but not outside of it. The medium property we assign to a this.medium. This is an important property in JS. ’this’ properties are available essentially public properties. We also have a var hunger, which is essentially private. As you can see, its used in the public functions for paint, feed and getHunger.
Scenario A
We create our new Arist. Next we ask for its name directly, and we are notified that it is undefined. Thats because the name property is private within the Artist function. To get the name, we need to call its getter function, getName(). We wanted the name to be read-only once our Artist is initialized. However, as you can see in SCENARIO A, you can still assign a new name property to our Artist. This doesn’t overwrite our artists actual name property.
Scenario B
Artists are typically starving, and our current artist is no exception. Every time our artist makeArt, he gets more hungry! The feed function takes a parameter and adds it to hunger. We don’t want a user to be able to manipulate hunger without feed or makeArt. Requesting to see hunger directly results in undefined.
Scenario C
Since we don’t care if the artist changes his medium at any time, that property was defined with a this in the constructor, and is there for a public variables.
Scenario D
Finally, we show that no matter what you do, JavaScript is a hugely dynamic language, and you just can’t save a developer from himself. You may able to make the logic in a function private, create getter/setters and make read-only properties, but all of that can be written over by just assign a new property to the function itself.
Thats all for now! I’ll continue to blog and write as I dive deeper into the language.
No CommentsApple's Orientation Lock UX Blunder
I love my iPad. I think Apple has put together a fantastic device, and if it had a complete web experience (aka Flash Player), it would be nearly perfect.
I think Apple could be hailed as the king of user experience (UX). With the release of iOS 4.2, Apple continued to improve the device. The addition of folders, multitasking and quick access to display brightness and volume were welcome additions. Apple did however make one huge blunder in their upgrade to iOS 4.2 – the changing of the toggle switch on the right side of the iPad from ‘orientation lock’ to a ‘system mute switch’ is completely wrong.
I use orientation lock a lot. When I wake up in the morning, I lock my screen so that I can read my e-mail while laying on my side in bed. Many of the documents I receive have some pages in portrait and others in landscape. When I’m drawing in apps, I lock the screen so I can flip it around to get different angles. Having quick access to orientation lock is important.
To lock orientation now, one has to double click the home button twice, slide the bottom menu over to the left, and click the orientation lock button.
The major problem with this is that you need to be able to have access to the system to lock it. So if you have having problems viewing the device at the current orientation, you’ll need to manage to unlock the device with a pass code and then navigate to the button.
If you can’t move the device easily it can be difficult to set the lock. My sister uses the iPad an augmentative communication device. Her fine motor skills, arm strength and accuracy to hunt and peck on the iPad are not great. I’d like to think she will be able to find and use the orientation lock button when she upgrades to iOS 4.2, but I have my doubts. Its extremely disappointing that this software upgrade will hinder ability to use the iPad to its fullest potential.
Bottom line: Orientation is a VISUAL problem, and thus if you can’t easily manipulate or see the screen because of its orientation having a physical toggle switch that doesn’t require the user to have a clear view of the screen is essential!
Now lets look at the mute switch… For the record this is a “System and Notifications Mute.” This is not a normal mute, which kills all audio coming from the iPad. If you are watching a YouTube video or playing iTunes, this switch will not silence that audio. The only noise this switch will prevent are notifications from other applications such as the ‘new mail ding’ and ‘ instant message’ noises. That way, if you are watching a movie you won’t be interrupted by other application and system sounds.
I don’t have a problem with this functionality, in fact I think its a necessity with a multitasking device. I do have a problem with the way Apple implemented. Firstly, most people see ‘mute’ and (I believe accurately) assume it will kill all the audio. The icon that shows up when you toggle the system mute toggle switch is a speaker with a slash through. There is nothing in that icon to identify that its not killing all audio. In fact, this new system-mute system is so unintuitive and so poorly communicated by Apple that even their own Genius Bar employees thought this was a mistake.
I upgraded to iOS 4.2 a few weeks back as a developer. I assumed that the reason the mute didn’t work, was because I had a developers version of iOS 4.2. When the real release came out, I upgraded again. The mute button still didn’t silence my iPad, so I took it to the Genius Bar at my local Apple store to get it fixed. The genius bar couldn’t figure out why the switch didn’t silence my iPad, and since I was still under warranty, they sent me home with a brand new iPad.
Let me state that again… Apple technical support sent me home with brand new iPad because they too thought the ‘mute switch’ was designed to silence all audio. Clearly this is not intuitive.
So how do I think this should be fixed? Quite simply really: The functionality of that switch is clearly software related since it changed with a software upgrade. Put the power in the hands of the user and give them the option of setting the toggle switch to “System Sound Mute” or “Orientation Lock”.
I urge Apple to listen to its users and give them the abilty to configure their device how it best suits them. You can give feedback directly to Apple at http://www.apple.com/feedback/ipad.html.
Update 1/17/2011: I just installed the iOS 4.3 beta, and the toggle switch can be either orientation lock or system sound mute. THANK YOU APPLE FOR LISTENING TO YOUR CUSTOMERS!
No CommentsClassic Snake In HTML5
While I’ve been developing Rich Internet Applications for the past five years, it has been a long time since I’ve had to program true HTML5, CSS and JavaScript. The last time I wrote a legitimate HTML based webpage, the industry standard was laying out the content in tables. Attempting to dive in and learn all the new pieces seemed daunting. I decided to start my focus on the Canvas component in HTML5 because of its relative closeness to the Canvas component in Flex.
My goal was to develop something that was animated, took advantage of keyboard and mouse clicks, and could be used on mobile devices. I created the classic game Snake. Use your WSDA keys to control the movement. Alternatively, for mobile devices without key support you can click in the top, bottom, right and left purple squares to move the snake in that direction.
[iframe: src="http://www.dcholth.com/html5/20101103/snake/snake.html" frameborder="0" width="410" height="410" scrolling="no"]
Drawing on the Canvas requires you to call the stroke() function. I feel silly even mentioning this, but it took me at least twenty frustrated minutes thinking my code wasn’t executing at all until I figured this out. If you do not call this function after creating your paths, nothing shows up on screen…
{code type=javascript}
gDrawingContext.beginPath();
gDrawingContext.strokeStyle = “#FF00FF”;
gDrawingContext.moveTo( 0, yB+ yB);
gDrawingContext.lineTo( gWidth, yB+ yB);
gDrawingContext.stroke(); /* CALL ME */
{/code}
Redrawing on the canvas is slow. At least it is on the iPad and my Droid Incredible. I had done a previous experiment where I had red squares bouncing all over the screen. This effect was made by redrawing both the grid and the red pixels each interval. While it looked smooth on my computer screen, it was extremely choppy on the mobile devices. To make the Snake game smooth, I’m only redrawing what is necessary. For the Snake, I’m drawing black squares over the tail, and adding red squares to the head to create the movement effect. I know that there must be ways to have smooth animations on mobile devices (I’ve seen them!) but they currently elude me. More research on this to come.
Clicking a Canvas within the mobile device browsers has a significant delay. While it does register the clicks, there is a delay between clicking, and having the snake change directions. I believe this is an issue with the touch screens trying to determine the intentions of the users finger on the screen within a browser. I’d like to do further tests to find out if this is something that I can fix, or at least predict exact delays. I noticed on the Droid Incredible, clicking the Snake game causes the entire Canvas to highlight green, as if its reacting to it like one big button.
There does not seem to be a ‘focus’ in HTML5 Canvas. I had originally programmed the game to use the arrow keys to control the direction of the snake. I had to change this because there doesn’t appear to be a way to differentiate that the arrows are supposed to control the Snake game (IE: The snake game has focus) and not the scrollbars of the webpage. So clicking down would send the snake in a downward direction, but it would also scroll your page down. This is a little difficult to see on my blog, because I am embedding the Snake game in an iFrame to make it work with WordPress.
Thats all for now! Feel free to browse the project code. The major code components to this application are:
- http://www.dcholth.com/html5/20101103/snake/snake.html
- http://www.dcholth.com/html5/20101103/snake/snake_code.js
MN.swf Camp April 5th
I will be giving a talk on light weight 3d development for Flash Player at MN.swf Camp on April 5th.
This should be a great event for anyone interested in the Flash Platform! Come check it out!
http://www.mnswf.com/camp10/index.cfm
No CommentsFlex Camp Phoenix & Wall Street
I had the privilege of speaking at Flex Camp Phoenix last week. I gave my presentation on an introduction to Flash Player’s built in 3D effects and functionality.
It was a great event! If you have an opportunity to attend a Flash/Flexp camp I highly encourage it. There was great presentations for both the beginner to the advanced developer. I have applied to give this presentation again at SWF Camp10 here in Minneapolis. Fingers crossed it gets accepted!
The project which I presented is displayed below. Read more
Flex Camp Wall Street
I gave a session “Introduction to Native 3D In Flash Player” at Flex Camp Wall Street this Tuesday. I’m going to do a bit more cleanup and documentation within my example code and will hopefully have all the slides & code before weeks end.
Thanks to all those who attended the event. It was a huge success!
One CommentPresenting tonight at Flash MN
I will be presenting at FlashMN at 6:30pm.
The talk will primarily focus on the challenges of working with Flash Player’s new x/y/z rotations, setting
perspective projections and masking in 3D space.
Flash Player 10 Rotation XYZ Fun
I’ve been playing around a lot with Flash Player 10′s rotation XYZ. After doing a series of experimentation and actually implementing it into a new project, I had some doubts about Adobe’s implementation of 3D.
Experiment #1: http://blog.dcholth.com/beta/RotTester/RotTester.html
The images are laid out in a grid, with each image’s rotations (XY & Z) being set to the values of the numeric sliders at the top. As you can see, each image’s perspective looks different, because they are placed in a 3D environment with the ‘camera’ being set to a specific point. I had a heck of a time figuring out how to set that camera!
If you look at http://livedocs.adobe.com/flex/3/langref/flash/display/DisplayObject.html#rotationX it says “Indicates the x-axis rotation of the DisplayObject instance, in degrees, from its original orientation relative to the 3D parent container.”
Well, in the example above, each image is placed in its own Canvas – my best guess was that the parent canvas should be its ’3D Container’ so the rotation should be based off of that, but clearly it was basing off some other point at the Application level.
I posted my frustrations with this a few places, and finally fellow Universal Minder, Ryan Graff came to the rescue, with the missing piece: PerspectiveProjection
Setting the PerspectiveProjection of your target’s Transform will give you the results I believe most developers will be looking for.
Experiment 2: http://blog.dcholth.com/files/PanelTest/PanelTest.html
The image in the TitleWindow on the left has its PerspectiveProjection set to be the center of the TitleWindow, where as the image in the TitleWindow on the right has the default properties. Notice that dragging the TitleWindow on the right around the screen results in distortion of the image, where the image on the left remains tilted exactly how we want.
Experiment 3: http://blog.dcholth.com/files/RotatorTest/RotatorTest.html
Back to our grid of images, here we set the images PerspectiveProjection to point towards the red dot. Drag it around the screen to see how it effects how each image is percieved.
In conclusion, I believe that most developers will want to take advantage of the PerspectiveProjection’s properties when working rotations of UIComponents in 3dSpace.
One Comment


