Home Page
Archive > Posts > 2010 > September
Search:

Android Graphics Methods
There isn’t always one best answer

Due to another new project I’ve been working on, I was able to test out different methods on rendering sprites on the Android platform.

  • Method #1: Use OpenGL ES to render to a buffer in C via JNI. This method turned out to be the fastest if polygons are batched via lists in a single (or a few) draw calls, and if using fixed instead of floating point numbers. It also opens up a lot of other effects natively not easily implemented through the other two methods (native 3D and matrices). However, it does not support antialiasing natively as is advertised and as I expected. The OpenGL ES 1.0 specs report “antialiased polygon rendering (with alpha border fragments, not multisample)”, but I could not find any information on this at all, and no antialiasing calls that I tried actually worked. There are methods that would allow antialiasing, but none efficient enough for a phone.
  • Method #2: Drawing directly to a pixel buffer in C via JNI. This method came in a very close second place if using memory copying functions to blit images, but that also removes a lot of important effects like translucency. Results were less than optimal when not using direct memory copies (I didn’t even worry about including them below) :-\.
  • Method #3: Rendering through the Android API in Java. While this method is the most robust in terms of feature set, it is also by far the slowest.

For my personal goals, I’ve come to the conclusion it would be best to use Method #1 for my heavy rendering tasks, and used baked translucent pixels around the borders in the images to emulate 2D antialiasing. The translucent borders could also be added at load time. I think I may also use Method #3 for some other special effects and overlays, though that will also make it harder to port, but I think worth it for now.


The following are the approximate average FPS results to the speed tests I performed (preceded by column descriptions):
  • The Test: 45*45 quads (2*45*45=4050 polygons) drawn to cover the whole screen each frame, none overlapping
  • Emulator/Droid: The tests were run on 2 separate systems. An Android emulator running v2.2 on my Intel core i5 2.53ghz laptop, and my Motorola Droid also running Android v2.2.
  • FLOAT/FIXED: This is only used on Method #1. OpenGL ES supports (in different functions) both floating point numbers and fixed point numbers. Since phones usually have no FPU, and the ones that do might have very slow ones, it’s much more safe efficiency wise to not use floating point numbers. The OpenGL ES solution was to have non-floating (fixed) point decimal arithmetic numbers that act virtually the exact same as normal integers when used with arithmetic functions, but do not have near the range as either floating point numbers or normal integers. The gain by going from floating to fixed was marginal in my tests. 16 bit integers (shorts), which I prefer, can also be used and showed near identical results to fixed point numbers.
  • INDIVIDUAL/ALL: This is only used on Method #1. It means whether all the quads were drawn individually in a different call for each (which draws 2 triangles to make a quad), or in 1 call from a list of all the triangles. The gain by going from INDIVIDUAL to ALL was ~1fps on the emulator and ~12fps on the Droid in my tests.

Emulator Droid
METHOD1+FLOAT+ALL 11.2 43.4
METHOD1+FIXED+ALL 11.5 44.2
METHOD1+FLOAT+INDIVIDUAL 9.7 30.4
METHOD1+FIXED+INDIVIDUAL 10.7 32.5
METHOD2 25.5 43.3
METHOD3 6.4 22.8
Laptop Reviews
I will be having nightmares about faulty laptop hardware for years to come

So for all of June and half of July this year I was in Canada for a really big contract. It was a very intense and taxing (though rewarding!) project that basically tied me up 24/7 for the whole duration, minus the little sleep I could afford, and acquiring food. Unfortunately, during this time, during a very hectic and somewhat dangerous part of the job, my Dell XPS M1730 laptop took a grand fall and cracked open. To its credit, it lasted for 10 more days, which completely saved my butt. During that time it only had minor touchpad problems which required a reboot when they started happening, but then it completely bit the dust on the final day of the project (I coped) due to, I believe, an electrical short somewhere on the motherboard.

The previous laptop I had the pleasure of using for 3 years was a Dell XPS M1710, which I absolutely loved in every way, besides the constant hardware failures and having to get replacement parts sent out each time they occurred. It conveniently bit the dust just before its warranty was up, so I was sent the previously mentioned M1730 by Dell as a replacement, which was unfortunately a refurb[ished], and never worked very well. Because of this it had no warranty, and coupled with the sub-par performance, I decided it was time to consider it totaled when it stopped working, retire it, and get a new laptop.

The new laptop process however ended up taking about 6 weeks to complete due to horrible hardware failures and service. My requirements for a laptop were very specific and there were only about 5 laptops on the market I could find that even fit my specs, which was very disappointing. Within those 6 weeks, I have had the chance to use and review 3 separate laptops, each from different companies, and will be including my positive and negative points about them below (in regard to the many other laptops I’ve used over the years). It can be assumed that anything that is not mentioned is as expected.

Toshiba Qosmio X505-Q888 TruBrite 18.4-Inch Laptop
  • Supplier: Bought from Amazon for ~$1,600. A full refund was issued upon confirmed hardware failure by Amazon (otherwise a restocking fee is applied). It was sent out immediately and received within 1 day.
  • Pros:
    • Huge 18.4” monitor
  • Cons:
    • The reason I was forced to return it was the monitor went bad in less than a week. The monitor would sometimes turn on after boot or a resolution change, but would always turn back off within 5 seconds. During the short spurts it was on, the colors were way off on half the screen. I did a lot of tests using an external monitor to try and fix the problem, but determined it was an unfixable hardware issue.
    • Media/control buttons were located on the left side of the keyboard. They were touch sensitive buttons that were way too easy to trigger accidentally. Simply relaxing my left hand usually caused it to brush and trigger one of the pseudo-buttons. I had been planning on writing a little utility that required either a double tap, or a prolonged hold, to trigger the keys, but ended up not needing to due to having to return the laptop.
    • The power cord disconnected way too easily. It probably averaged coming out of the power slot about 3 times an hour with little movement of the laptop.
    • It had very bad overheating problems consistently, but especially when playing games. I believe this might have caused the failure of the monitor.
    • The speakers would cause the volume to fluctuate very randomly so music was always distorted as it increased and decreased in volume every few second or so.
Dell Studio 17
  • Supplier: Bought from Dell for ~$1,800 including extended 3 year mid-tier warranty and a few hardware upgrades. A full refund was issued upon return. Dell originally lied to me about the amount of time it would take to arrive and I almost canceled the order before it was sent out because of this.
  • Pros:
    • The media buttons were in a very unobtrusive place (the best of any laptop I’ve ever had).
    • The laptop was probably half the weight of any other laptop I’ve had of its size, and the power supply was probably about a sixteenth the size of any power supply for same said previous laptops.
  • Cons:
    • It’s Dell...
      • Dell has absolutely ABYSMAL phone support. It’s outsourced to India and the “representatives” are completely unknowledgeable and virtually unintelligible. The representatives and managers have absolutely no power to get anything done, and even the managers are now Indian so you can’t even escalate to a comprehensible conversation. The representatives do virtually nothing but read prompts from screens, and for knowledgeable computer users, it’s painful to explain to them you don’t need them to try and diagnose the problem as you already have, but they want to guide you through their script via the phone anyways. During the calls for this laptop I was even told at one point I would have a 2 hour wait time to talk to a manager, and I experienced so many dropped calls I stopped counting. Dell support was the worst in the industry 2 years ago. Since then, it’s gotten twice as bad. I will never use or recommend Dell again to anyone for this reason.
      • Before I gave Dell my credit card number and committed my order, I had been told by the website the laptop would ship immediately and I would have it within 2 days. Immediately after I committed to buying it, the website suddenly told me it would instead take OVER 3 WEEKS for me to receive it. I was flabbergasted, and this was the reason I spent hours with phone support over many days trying to get this fixed. I finally decided to cancel the order and get another laptop on the 6th day, but I guess due to my demands, they actually shipped it right before I was about to call, aborting my attempt. It arrived 8 days after I made the order, which still caused me major problems.
    • The hard drive had major freezing problems, which is what eventually made me return the laptop, as I did not want to have them send me a completely new Chinese assembled one, as it would take forever and most definitely be a refurb. The freezing even occurred during BIOS, and it often took up to 4 minutes to resume from hibernation.
    • The ATI video card was less than optimal compared to the nVidia cards on my other recent laptops. It just wasn’t performing in games.
    • The power cord was ridiculously short, was prone to falling out (not nearly as much as the Toshiba), and had a power led on it that was much too bright (it actually kept me up at night if left on).
    • The speakers were in a horrible spot on the palm rests. Having my wrists in the proper and comfortable position for the keyboard covered them up causing bad distortion and dampening.
    • The touchpad was far too big and had no dead zones in the touchpad driver properties. Because of this and the horrible over sensitivity of the pad, it was very hard to use as it often stopped working when it detected “multiple touches”. Even an apple charger cord barely touching it made it stop working.
    • There was no property key or pause break key (Even via a “Fn” key combo).
    • There was no indicator light for the caps and num locks.
    • Many of the keys started squeaking after a few days.
MacBook Pro 17-inch
  • Tired of horrible hardware from other companies, I decided to give in and get a MacBook Pro against my better judgment. It has turned out to be the keeper simply because I’m tired of dealing with finding a laptop and I hear they have spectacular technical support including (supposedly) often receiving your laptop back within 3 days of sending it in for hardware replacement!
  • Supplier: Bought from Apple for ~$3,100 including extended warranty and a few hardware upgrades whole sale (RIDICULOUSLY expensive). However, I had a 15% friends and family discount through a friend who is an employee of Apple bringing the total down to ~$2,600. There is no way I would have gotten it without the discount, but even with, it was still hideously expensive for what you actually get. I received it within 7 days as I was told.
  • Pros:
    • It actually has a 1920x1200 (WUXGA) resolution! Both of my previous Dell’s had this, but the only 2 computers I could find on the market currently with this that fit my specs were the MacBook Pro and an Alienware (which is Dell and also ludicrously expensive). The next step down I was forced to accept on other computers was 1920x1080 (Full HD/FHD/1080p).
    • The magnetic power connector is WONDERFUL. It never falls out!
    • The visible battery meter on the side of the computer is kind of nice, but I doubt I’ll ever use it.
    • I was able to get a matte screen for an extra $50. I HATE (but have always had to deal with) glossy screens because you often can’t see them if the sun is shining on your screen, and they are fingerprint magnets.
    • The time the computer can run off of battery seems pretty amazing. Windows is reporting almost double the amount of battery time as normal laptops, which seems to be accurate, though I have not fully tested this.
  • Cons:
    (Most all regarding running in Windows on the MacBook Pro, which is what I pretty much only use it for)
    • The touchpad has virtually no settings and works absolutely horribly in Windows.
      • Some example settings most all other touchpads have, some of which are available for this touchpad in OSX include: sensitivity, dead zones, and scroll zones.
      • The available settings in Windows are: Tap to click, dragging, drag lock, which bottom corner is considered a secondary click, two fingers resemble a secondary tap.
      • The multi-touch nature mixed with the absolute farce that is the Windows drivers for the device is what causes the main problem. There are no separate mouse buttons, and it’s basically unusable to utilize the bottom left and right sides as buttons with all the glitches. I think I might end up trying to write my own drivers for it for Windows soon, and if that doesn’t work, I will attempt finding a mouse buttons peripheral I can plug into via USB.
      • The touchpad will not allow a right (secondary) click while another finger is also touching it, and the secondary click via 2 tapped fingers is very unstable. It also seems right clicking sends a left mouse down event (but not a left mouse up event), which often cancels context menus.
      • For the touchpad to be usable I have to make sure to keep only one finger on it at a time or it gets buggy.
      • I did research on the Apple multitouch touchpad a few nights ago and apparently Apple didn’t really support using the touchpad at all in windows until like 2009, and that was only a token gesture as they just don’t give a shit about the drivers, only making them barely usable to allow advertising Windows compatibility.
    • The keyboard key set is only a subset of a normal keyboard and missing a ton of keys:
      • No number pad (though many laptops do not have one)
      • A few of the missing keys are: Page up, page down, home, end, print screen, insert, delete (only has a backspace labeled as delete). Missing keys are mostly all replaced by “FN” key combos via Boot Camp, though not all of them are listed in the Boot Camp help file.
      • Due to the missing keys and the non standard layout of the Mac keyboard, I used KeyTweak to remap a good number of keys for my purposes. There is also a program available in the Windows Server 2003 Resource Kit Tools that accomplishes the same task, though with a worse GUI, called Remapkey.exe. Both of these programs just modify a registry value that has windows natively remap the keys. I also had to use a modification of my HalfKey Project for some other key remappings.
      • The “Fn” and “Eject CD” keys are hard wired and can’t be remapped through the above method. This has caused me a lot of annoyance so far as “Fn” and the left “Control” keys are swapped from standard layouts.
    • There is no way in Windows to disable/mute the startup sound when the laptop is turned on (which I find incredibly annoying and embarrassing in public venues). Fortunately, this can be fixed by running the 3rd party StartupSound.prefPane configuration dialog in OSX just once.
    • EFI adds another layer that can be used as a security weak point, invalidating my last security scheme. It didn’t work off the bat anyways as the EFI wouldn’t boot to the USB running GRUB, as I believe GRUB for EFI is required.
    • The keyboard backlight doesn’t work until the OS has loaded making the keyboard unviewable in dark situations. The monitor brightness is also unadjustable until Windows loads, and uses the last brightness set by OSX.
    • There are no drivers for the light sensor in Windows (though I personally don’t care about that).
Combining an Android Project's Versions
Or: “Realtime Project Version Syncing”
As noted in a previous post:

Seeing as there are a number of applications on the market that have both a “Free” and “Full” version, you’d think this would be an easy thing to accomplish. Unfortunately, the marketplace uses an application’s package name as its unique identifier, so both versions have to have a different package name, which is again, a bit of a nuisance.

One method of remedying this is just having a recursive string replace through all the files [...]


I spent a bit of time coming up with a solution for this a few months ago for my latest project, [TEMPORARILY DOWN**]. This solution uses a shared package with a shared code base and resources that the different project versions pull from.


**The project that is a great example of how this process works should be uploaded very soon. At that time this message will disappear and appropriate links will be added. You’ll know this has happened when I upload my next project.


The steps for this setup are as follows: (The source for [TEMPORARILY DOWN**] can be used as an example)
  • First some definitions that will be used below*:
    • ProjectName: The base name of the project (e.g. “MyAndroidProject”)
    • VersionName: The name of separate versions (e.g. “Free” and “Full”)
    • SharedName: The name of the shared section of the code (e.g. “Shared”)
    • BasePackageName: The base name of the package group (e.g. “com.example.MyAndroidProject”)
    • BasePackageDirectory: The base path of the package group (e.g. “com/example/MyAndroidProject”)
    *Please note these definitions are used in code sections below.
  • Create the directory structure:
    • A base directory of ProjectName (e.g. “~/MyAndroidProject”)
    • A subdirectory under the base directory named SharedName for the shared files (e.g. “~/MyAndroidProject/Shared”). It will hold any shared files in appropriate Android standard directories (e.g. “res”, “src”).
    • Subdirectories under the base directory named VersionName for each version’s project (e.g. “~/MyAndroidProject/Free”). Each of these will hold its own complete project including the AndroidManifest.
  • Creating the shared resources: There’s nothing special about shared resources (probably in “SharedName/res”), except I suggest noting at the top of the files that they are shared, for reference sake.
  • Creating the shared code:
    • Shared code goes in “SharedName/src/BasePackageDirectory/SharedName” (e.g. “~/MyAndroidProject/Shared/src/com/example/MyAndroidProject/Shared”).
    • As noted for shared resources, you might want to note at the top of the files that they are shared.
    • Set the package name for shared code to “BasePackageName.SharedName” (e.g. “package com.example.MyAndroidProject.Shared;”).
    • Shared code should never directly refer back to a version’s package (non shared) code except through reflection.
    • Resource IDs are still accessible in this shared package through the “R” class, but when accessed the function or class that does the accessing needs to be proceeded with “@SuppressWarnings({ "static-access" })”. The “R” variable also has a “Version” member that can be used to alter shared code flow depending on the version being used. This will be explained more in detail later.
    • *BONUS*
      If shared code needs to access information from a static member in a non-shared class, reflection can be used, for example:
      Class.forName("BasePackageName."+R.Version.name()+".NonSharedClassName").getDeclaredField("StaticMemberName").get(null)
      A static function can be called in a similar manner through reflection:
      Class.forName("BasePackageName."+R.Version.name()+".NonSharedClassName").getMethod("StaticMethodName", new Class[0]).invoke(null);
  • *BONUS* Global Shared Class: I also suggest having a shared class that holds global variables that allows easy interaction from the shared to non shared classes, and holds static information that both use, with members including:
    • A reference to a Context (or Activity) from the main program
    • The BasePackageName (needed for reflection, and other stuff like preference storage)
    • Other useful interfaces like logging
  • Creating the non-shared code:
    • Create a separate project for each version in their corresponding subdirectories listed in the third step of the Create the directory structure" section above.
    • Make the package name for a version as “BasePackageName.VersionName”.
    • When referencing shared classes form an android manifest, make sure to use their full package name, for example, a shared activity would look like “<activity android:name="BasePackageName.SharedName.ActivityName">
    • Import the shared package into all non-shared class files “import BasePackageName.SharedName.*;
  • Linking the shared code into each project:
    • The shared code now needs to get integrated into each project. To do this, all the shared files need to be symbolically (or hard) linked back into their corresponding directories for each version.
    • First, make sure each project directory also contains the same subdirectories as those found in the shared directory.
    • The script I have written for this, which needs to be put in the base directory, is as follows: [EDIT ON 2011-01-03 @ 6:28am] See here for a better copy of the script. [/EDIT]
      #!/bin/bash
      
      #Run this file to install links to shared files into all branches
      
      LN="ln" #Use hard links, which work well in Windows and require less logic to calculate linking
      
      #if [ `uname || grep -vi 'cygwin'` ]; then #If not windows (NOT YET SUPPORTED)
      #	LN="ln -s" #Use symbolic links, which take some additional logic that is not yet programmed
      #fi
      
      LocalBranches=`find -maxdepth 1 -type d | grep -iPv "^\.(/SharedName|)$"` #Find version names, ignoring "." ".." and the shared directory
      
      #Propagate shared files into different versions
      cd Shared
      for i in $LocalBranches; do
      	find -type f -print0 | xargs -0 -i rm -f ../$i/{} #Clear out old links from version just in case the link has been undone
      	if [ "$1" != "clean" ]; then
      		find -type f -print0 | xargs -0 -i $LN {} ../$i/{} #Link shared files into directories
      	fi
      done
      				
  • Tying the resources together:
    • The resources IDs in the “R” class might need to be accessible by the shared classes. To do this, an “R” class needs to be added into the shared namespace that duplicates the information. Unfortunately, the Android generated resources ID class “R” marks everything as “final” so class duplication requires a bit more work than would be preferable.
    • Each different version needs its own “R” class, put into the directory “~/MyAndroidProject/VersionName/src/BasePackageDirectory/SharedName” that the shared code reads from.
    • This class will also contain version information so the shared classes can know which version it is currently interacting with.
    • The code is as follows:
      package BasePackageName.SharedName;
      
      import BasePackageName.VersionName.R.*;
      
      public final class R //Mimic the resources from the (non-shared) parent project
      {
      	//There may be more resource ID groups than these that need to be shared
      	final static attr attr=null;
      	final static drawable drawable=null;
      	final static id id=null;
      	final static layout layout=null;
      	final static string string=null;
      	final static xml xml=null;
      	final static array array=null;
      	
      	public enum Versions { Version1, Version2 }; //List versions here
      	
      	public final static Versions Version=Versions.CurrentVersion;
      }
      			
    • Whenever this “shared” “R” class is accessed, the function or class that does the accessing needs to be proceeded with “@SuppressWarnings({ "static-access" })”. This is due to the hack required to reproduce the “final” class information from the original “R” class into a shared class.
  • Working with shared projects and code in Eclipse:
    • When modifying shared code in Eclipse for any of the different versions, other version’s projects need to be refreshed to pick up the new code. I tried many different methods and processes to fix this different package name problem but this described method is still much quicker and easier than any of the others.
Android Permissions Improperly Reported
More Android stuff, with even more to come soon
[EDIT ON 2011-01-03 @ 1:32AM]

A fix for this issue has been recommended and I consider it resolved. There was always a fix for this but it had not been given yet, as there was confusion to the problem in the bug report. Other people are still reporting the problem but I cannot reproduce it after the suggested fix.

[END OF EDIT]

It has come to my attention that my Mini Acuity application suffers from a “known defect” in Android, namely, that it “requires” 2 security permissions I did not ask for or use.

The “Storage” and “Phone Calls” permissions are listed in the “Application Info” in the Android settings dialog even though the market does not specify that they are used during install.

This is a result of using an old SDK version as the base of my code. Google actually encourages authors to use the minimum possible SDK version, as Android is backwards compatible, so that as many users as possible are supported. This means my only solution to not having these security permissions listed would be to upgrade the SDK version, thereby disabling compatibility from some older phones. I wish there was a way I could see the distribution of Android Versions for my application’s downloads to help determine if this would be worth it.

I have updated the Mini Acuity project page accordingly with a “Permissions” section.

On a side note, it occurs to me how much of a security hole this [possibly] is. If an application is running on these old SDK versions, and the user sees an application has only network access permission, they might not worry about the application stealing their data while it could! Though, I have not yet done the research to confirm this, or plan on doing so. I feel more and more that Android’s security system leaves a lot to be desired.