Tuesday, 21 September 2010

HTC launch event - Desire HD and Z

HTC got friendly last week having a launch party for their yet unreleased Desire HD and Dersire Z phones. The phones are nice and light (maybe slightly too light) models with WVGA screens (the desire HD has a larger screen at 4.3").

The event was a bit misguided - the phones were in a separate room, in which only a few people were allowed to view them at a time. I think a better marketing technique would've been to have more phones so everyone that went could get a better look at them. It was quite annoying going to see new phones and not really being able to get a sense of what they feel like to use for a while. If you're going to spend all that money on marketing, then more actual phones definitely couldn't hurt, but who would say no to free food and beer anyway ...

The Desire HD borders on a mini-tablet device with such a large screen, though it is still very much a (big) phone. It also has the very nice feature of a built in DNLA server, which I am looking very forward to. Hopefully it will play nicely with MyPOD so you can easily have videocasts on your main TV. It is certainly a nice feature to have for a media device though, videos can be viewed without cables. I'm guessing more recent TVs have this DNLA client functionality built in, but I use my PlayStation which works fine (I haven't had a chance to test it with the device unfortunately).

The desire Z is slightly lower power (800MHz), and has a nice looking slide out keyboard.

The phone specs are available here:
HTC Desire HD

HTC Desire Z

Thursday, 16 September 2010

DroidCon London 28-29 Oct, 2010

The upcoming London DroidCon conference looks very promising, the people at Novoda (and others I'm sure ..) have put together an excellent programme of speakers and topics, especially in the user experience and business marketing side. I would highly recommend it for people who are looking to develop their ideas on Android.

These events are very important for the Android community to meet face-to-face and discuss ideas and strategies, and the Barcamp on the first day is a good way to incubate such ideas.

DroidCon events have been held in London and Berlin for the past two years and with the quickening pace of Android development and market penetration, it looks to continue as a premier event for the Android community.

http://www.droidcon.co.uk/

Saturday, 11 September 2010

Android vs Oracle contradictions

There has been a lot of talk in the tech world about Oracle's patent infringement claims against the Android operating system. Oracle have not disclosed the details of the claims, and are highly unlikely to do so before the case goes to court. While I respect the right of Oracle to protect it's intellectual property, it seems this non-disclosure is more aimed at scaring people away from Android, even though ultimately they will be seeking some form of licensing arrangement for whatever patents/copyrights have been infringed in Android.

The best thing Oracle can do at the moment is to disclose the basis of their claims, not only are they hurting Android but they are also hurting the open-source Java community in its entirety, and in doing so the value of arguably the biggest asset they acquired in their takeover of Sun (i.e. Java). One wonders how they can't see this, possibly they think Java is too big to fail now (sound familiar?).

The whole thing rings of the IBM vs SCO case of a few years ago. They made claims Linux infringed their patents, would not disclose any information about it and then when the case came to court, they didn't really have much to stand on. SCO eventually filed for chapter 11 bankruptcy protection and looks like it will go out of business. The lesson that could have been learnt is that these frivolous patent claims cost everyone money and to proceed you would want to be quite sure of wining, even though the lack of disclosure indicates they aren't really that sure.

It all adds a lot of weight to the argument that the patents system needs drastic reformation for use with software, which is re-used as a general development practice. Until this happens patents will be used as a tools for revenue generation and most likely result in mutually assured destruction for businesses looking to (mis)use them for revenue generation purposes.

Wednesday, 8 September 2010

MSc Project presentation

I have recently completed a MSc in Digital Music Processing at Queen Mary University in London. My final masters project was a implementation of beat detection and mixing on Android, which included a thorough analysis on onset detection, tempo analysis and beat recognition, as well as a custom Phase Vocoder implementation. The project went quite well and a good result was achieved, though in 2 months it is quite hard to complete a large implementation. The project had a healthy proportion of NDK programming in it, which was really interesting and my first use of JNI, definitely a necessity for apps needing a DSP component on Android.

The project was presented as part of the university evaluation process and is even being considered for inclusion as part of a new project to make mobile technology @ Queen Mary available to all.

For anyone interested in the gory details - I have included the final project report and presentation.

Thursday, 12 August 2010

MyPOD hits 50K ...

MyPOD the podcast player by sentinel web technoloiges has recently passed the 50K downloads barrier over the last week. So congratulations to us, stay tuned for more updates in the future.

While there are many apps that have hit the 50K barrier by now, each rung on the download ladder gives more confidence to users (to try it out) and developers (to add features).

I've got a feeling the 250K will be hit a lot quicker ;)

Tuesday, 22 June 2010

Anroid UI setInterval

In most apps I develop, I usually have a need to update the UI within the activity (as services change, or just live time displays). Making these timers is easy in Javascript, you just use setInterval(method,nnn).

On Android it is more complex - you need a Timer and TimerTask, and then you need another Runnable to give to Activity.runOnUiThread(..), and then your actual method. It all adds a lot of code bloat, especially if you have a few activities in your app. AsyncTask is good for updating the UI while a background process is running, but for just a simple update interval it's no use.

This is a reasonably simple solution to the problem - the MyTimer class has a setInterval method that behaves similarly to Javascript. The usage is:
  • Set the timer:
    int timer=MyTimer.setInterval(this, "updateUI", 2000,true);
    (where "updateUI" is a method with the signature: public void updateUI() {..})
  • Cancel the timer:
    timer=MyTimer.cancelTimer(timer);
Some Notes:
  • The cancel operation returns -1 if the cancel was performed successfully, so you can just test if the timer ==-1 to tell if you need to start it again.
  • The code above is called from the activity, the first argument of setInterval should be an Activity object.
  • There is a static debug variable if it doesnt work as expected (MyTimer.debug=true).
  • If there is an exception in the target method -> the timer is cancelled.
  • MAKE SURE YOU CANCEL THE TIMER (in onStop or onPause). If the timer is not cancelled, then it will prevent garbage collection, a possible way around is just to return the Timer object instead of holding it in a Vector.
  • Note that this type of usage can potentially use a lot of battery if its just left running, the updateUI method (or whatever the method name is), should do the minimum processing necessary. It should just update a couple of UI elements or something - not do masses of calculations (store results as variables is a simple solution).
package co.uk.sentinelweb.util;
/*
* licensed under CC BY-SA : http://creativecommons.org/licenses/by-sa/3.0/legalcode
*/
import java.lang.reflect.Method;
import java.util.Timer;
import java.util.TimerTask;
import java.util.Vector;

import android.app.Activity;
import android.util.Log;

public class MyTimer {
public static Vector timers = new Vector();
public static boolean debug = false;// turn on to check timer activates and cancels
public static int setInterval(Activity object,String method,int interval,boolean isUI) {
Timer timeoutTimer= new Timer();
TimeoutTask timeoutTimerTask;
try {
timeoutTimerTask = new TimeoutTask(object,method,isUI,timeoutTimer.hashCode());
if (debug) {Log.d(MyTimer.class.getSimpleName(), "timer created :");}
} catch (Exception e) {
Log.d(MyTimer.class.getSimpleName(), "error creating timer :"+method,e);
return -1;
} 
timeoutTimer.scheduleAtFixedRate(timeoutTimerTask, 0, interval); 
timers.add(timeoutTimer);
return timeoutTimer.hashCode();
}

public static int cancelTimer(int code) {
Timer timeoutTimer = null;
for (int i=0;i<timers.size();i++) {
if (timers.get(i).hashCode()==code) {
timeoutTimer=timers.get(i);
}
}
if (timeoutTimer!=null) {
timers.remove(timeoutTimer);
timeoutTimer.cancel();
timeoutTimer.purge();
if (debug) {Log.d(MyTimer.class.getSimpleName(), "timer deleted :");}
return -1;
} else {
if (debug) {Log.d(MyTimer.class.getSimpleName(), "timer not found :"+code);}
}
return code;
}

private static class TimeoutTask extends TimerTask {
Activity targetObject;
Method targetMethod;
Runnable invoker;
int code ;
public TimeoutTask(Activity targetObject, String targetMethod,boolean isUI,int code) throws SecurityException, NoSuchMethodException {
super();
this.targetObject = targetObject;
this.targetMethod = targetObject.getClass().getDeclaredMethod(targetMethod, new Class[]{});
this.code=code;
if (isUI) {
invoker = new ThreadRunner(this.targetObject,this.targetMethod);
}
}

@Override
public void run() {
try {
if (debug) {Log.d(MyTimer.class.getSimpleName(), "invoke timer :");}
if (invoker==null) {
targetMethod.invoke(targetObject, new Object[]{});
} else {
targetObject.runOnUiThread(invoker);
}
} catch(Exception e) {
Log.d(MyTimer.class.getSimpleName(), "error invoking:"+targetMethod.getName(),e);
cancelTimer(code);
Log.d(MyTimer.class.getSimpleName(), "timer:"+code+" has been cancelled");
}
}

}

private static class ThreadRunner implements Runnable{
Activity targetObject;
Method targetMethod;

public ThreadRunner(Activity targetObject, Method targetMethod) {
super();
this.targetObject = targetObject;
this.targetMethod = targetMethod;
}

@Override
public void run() {
try {
targetMethod.invoke(targetObject, new Object[]{});
} catch (Exception e) {
Log.d(MyTimer.class.getSimpleName(), "error invoking:"+targetMethod.getName(),e);
}
}
}
}
CAVEAT: While I haven't found anything in the API to do this (easily), it is possible that it is in there somewhere. If it is then let me know, and I'll update this.

This code is made open under the CC BY-SA licence.

Wednesday, 21 April 2010

Has to be done really ...


                    *                        *                      
                     *                      *                       
                      *   **************   *                        
                     ************************                       
                   ****************************                     
                **********************************                  
               ******    ****************    ******                 
              ********   *****************  ********                
             ****************************************               
            ******************************************              
            ******************************************              
                                                                    
  ******                                                  ******    
 ********   ******************************************   ********   
 *********  ******************************************   *********  
 *********  ******************************************   *********  
 *********  ******************************************   *********  
 *********  ******************************************   *********  
 *********  ******************************************   *********  
 *********  ******************************************   *********  
 *********  ******************************************   *********  
 *********  ******************************************   *********  
 *********  ******************************************   *********  
 *********  ******************************************   *********  
 ********   ******************************************   ********   
  ******    ******************************************    ******    
            ******************************************              
            ******************************************              
             *****************************************              
               ************************************                 
                     *********       *********                      
                     *********       *********                      
                     *********       *********                      
                     *********       *********                      
                     *********       *********                      
                     ********        ********                       
                      *******         *******