Category Archives: Android

Off-Market Android Installation Instructions

20 Sep 2012

I keep having people asking me how to do this. This is certainly covered exhaustively on the Internet here and there… but here’s yet another step-by-step on how to install Android Apps (APK’s) outside of a marketplace such as Google Play or GetJar. Note that it usually not a good idea to install non-market apps but in some cases its necessary, such when sending a demo build to a client, etc:

How To Install an APK onto an Android Device

STEP ONE: ENABLE OFF-MARKET INSTALLS

By default all Android devices will only install applications from Google Play. To install an APK outside of Google Play you must enable the ability on the device.

  1. Settings
  2. Security
  3. Unknown Sources – Allow installation of non-market apps <<< make sure
    this checkbox is checked as illustrated in the image below

STEP TWO: DOWNLOAD THE APK

There are a couple of ways to do this:

  1. Download from a website
  2. Plug your phone into your computer and then copy the APK from your computer to your device

STEP THREE: DOWNLOAD A FILE MANAGER

Download a File Manager so that you can browse your file system to locate and install the APK. There are two good free file managers in the Google Play market, one is “Astro” and the other is “ES File Explorer”, I prefer the later.

  1. Launch the Play Store
  2. Search for “ES File Explorer”
  3. Install the app

  1. Launch the app – by default ES File Explorer starts out showing files in the root of your SD Card (on my Galaxy S2 this is the case)
  2. Locate the file that you downloaded/copied to your device
    • If you downloaded the APK, it is likely in your “download” folder. Scroll down and locate “download”, and open the folder
    • If you downloaded the APK, it might also be in your external sd “download” folder. Scroll down and locate and tap “external_sd”, then tap the “download” folder that may be in that location
    • If you copied the APK from your computer to your device then you likely copied it to the external sdcard on the device. In this case scroll down and tap “external_sd” or similar. Locate your APK. Note that folders are displayed first, files second, so if you dropped the APK into the root of the external sd then it’s at the bottom of the list, just scroll down. If you created a folder for the APK then naturally you will need to locate and open that folder

STEP FOUR: INSTALL THE APK

Once you locate the APK simply tap it and install.

Playing Audio in Android/iOS Web Apps

11 Sep 2012

If you’re familiar with the state of HTML5 in Android land you know that many CSS3 features are not supported, among them is the AUDIO tag. There is a library out called SoundManager2 that claims to offer a “reliable cross-platform audio” solution but after trying it on mobile platforms I think it falls short of that promise.

SoundManager 2’s approach is to use HTML5 where possible with Flash as a fallback mechanism. Makes sense for desktop OS’s, not so much for mobile. iOS, even with its own quirks (no inline playing, no autoplay, etc) has functional HTML5 audio/video so that’s not much of an issue. Android is very different in that the HTML5 AUDIO tag is not implemented. Flash exists on Android but that has its own issues, among them: we are forced to assume that the Flash Player exists on the Android device in the first place which isn’t always the case. Add to that the fact that many users have to install the Flash Player manually on their devices as there is an absence of any auto-install capability. The final nail in that coffin is Adobe’s abandonment of the Android Flash Player altogether meaning no one can install it.

SoundManager 2 can no longer claim to be useful for mobile when its completely unusable on Android. Maybe when a version of Android with HTML5 Audio support takes the lion’s share of the Android ecosystem SoundManager 2 may again have use within the mobile space.

In any event, as mentioned, the lack of HTML5 AUDIO tag support continues to make supporting sound in Android Web Apps a challenge. The solution I’ve come up with (not that its a novel one) is to use the HTML5 VIDEO tag instead. VIDEO has support at least back to Android 2.2. Most events are supported though some don’t do quite behave in the manner that you would like for them to which makes the creation of a custom audio player somewhat of a challenge. In the end you may just have to bail on some lofty ideas/features that you may have for your own custom player but at least you can still get some sound working reliably.

It has been said that you can in fact feed the VIDEO tag an MP3. However, what happens within Android differs across its varied flavors. In Android 2.2 what will happen is that Android will not play the audio in-page but instead launch the native media player – and what you have is a black screen, devoid of controls albeit with your MP3 playing. In Android 4 you can get MP3 audio to work inline.

Due to the different behaviors and presentations between Android versions I’ve personally switched to using video files(mp4) to deliver sound. The result is that in Android 2.2 the native media player will display the video content – an image keyframed every second – which satisfies some mystery requirement that allows the on-screen controls to appear. This is much better than a black screen. On Android 4 we don’t care about the visual aspect of the video because my implementation avoids it entirely.

The concept is to use single VIDEO tag that is placed off-screen, use Javascript to change its src and control the sound via the relevant HTML5 media events.

It is important to note that some VIDEO tag attributes are necessary for this to work as without them you’ll be greeted by silence. Below is the HTML to use:

...
<video id="videoEl" autobuffer height="10" width="10" controls style="position:absolute;top:0px;left:-99px;">
  <source src="something.mp4">
</video>
...

The autobuffer is there because it can’t hurt. The one thing that is necessary is the presence of the video controls (yes, even though you won’t see them). Otherwise this is all pretty simple – you can see that the VIDEO tag is placed off screen.

I won’t post my complete setup as thats a bit of code, however, here’s a great start; first some HTML to be styled however you like:

...
<ul id="songs" class="music_list">
  <li src="vid/song_1.mp4">This is song number one</li>
  <li src="vid/song_2.mp4">This is the second song</li>
  <li src="vid/song_3.mmp4">Number three</li>
  <li src="vid/song_4.mp4">The last song</li>
  <li qwe="noSound">Just a list item, no video/sound to play here</li>
</ul>
...

In this case I’ve elected to keep the URL to the video in the LI tag. Here’s my JavaScript that utilizes the above, populates the VIDEO src, and controls the VIDEO (our sound):

...
var videoPlayer = (function(){
  var _isPlaying = false;
  var _elTarget;
  var _video;
  function _resetAllVideoStyles(){
    var lists = document.getElementsByTagName('ul');
    for (var i=0;i<lists.length;i++){
      if (lists[i].getAttribute('class').indexOf('music_list') != -1){
        var desc = lists[i].childNodes;
        for (var j=0;j<desc.length;j++){
          if (desc[j].nodeType == 1){
            desc[j].setAttribute('class','');
          }
        }
      }
    }
  }
  function _ifOldAndroid(){
    return navigator.userAgent.indexOf('Android 2.3.3') != -1 ? true : false;
  }
  function _loadVideo(t,str){
    t.setAttribute('class','mp_selected');
    _video.src = str;
    _elTarget = t;
    _video.load();
    setTimeout(function(){
      _video.play();
      _isPlaying = true;
    },1000); // NECESSARY timeout, play too soon and nothing will happen
  }
  function _stopVideo(){
    _video.pause();
    _isPlaying = false;
    _resetAllVideoStyles();
  }
  function init(v_id){;
    var el = _video = document.getElementById(v_id);
    el.addEventListener('error',function(){
      console.log('Cannot load the file');
    });
    el.addEventListener('pause', function(){
      console.log('paused/stopped');
    });
    el.addEventListener('loadstart', function(){
      console.log('starting to lo
    });
    el.addEventListener('play', function(){
      console.log('playing');
    });
    el.addEventListener('durationc
      console.log('duration changed');
    });
    el.addEventListener('progress', function(){
      console.log('progress: file is being downloaded');
    });
  }
  function dispatcher(t,str){
    if (t == _elTarget){
      _elTarget = null;
      _stopVideo();
    } else if (_isPlaying){
      _stopVideo();
      setTimeout(function(){
        _loadVideo(t,str);
      },100);
    } else {
      _loadVideo(t,str);
    }
  }
	
  return{
    init:init,
    dispatcher:dispatcher
  }
})();
window.addEventListener('load',function(){
  var list = document.getElementsByTagName('li');
  for (var i=0;i < list.length;i++){
    if (list[i].getAttribute('qwe') !== 'noSound'){
      list[i].addEventListener('click',function(e){
        videoPlayer.dispatcher(e.target,e.target.attributes[0].nodeValue);
      },false);
    }
  }
},false);
...

As you can see events are bound to all qualifying LI tags – the qualifier being that the parent UL must have a class called “music_list” assigned to it.

Thats a decent start for you – all the events are setup – you will quickly see that they don’t really fire when you expect them to. For example, the onplay event seems to start as the video is buffering, not when the video actually starts to play. ondurationchange may fire more than once – etc…. so as i mentioned before making a slick UI will be a bit of a chore. One thing that should be useful, though granted maybe not a cureall is the video.paused property. At least you will know when the video is playing or not, but as I already noted the video is considered playing when what I believe based on observation is buffering and not actual playing.

As far as iOS the video does not play inline, rather, the native video player will come up full screen. This happens because contrary to every other mobile browser Apple has decided in its totalitarian wisdom to buck the standard and suspend the mobile app in favor of its built-in media player. That’s a rather ironic tactic IMO as they profess to be on the side of HTML 5 & standardization but as usual they change the game per their whim and there’s nothing that can be done about it. Apple gives no explanation for this so it is what it is.

So that’s about – doing the above gets you something that works on both major mobile OS’s – Android with its caveats, and iOS with its mobile media player hijacking the

Losing Device Connection in Eclipse

20 Jun 2012

There may come a time where you will encounter an “AdbCommandRejectedException error: device not found” while trying to upload your app to your device from within Eclipse. This message will appear in the console and will be accompanied by this text: “Error during Sync: An established connection was aborted by the software in your host machine”. As a result you will be unable to install your app. Opening DDMS will show that the device is not connected to your computer a it simply doesn’t appear in the device list even though the phone is in fact physically connected.

To further illustrate:

To resolve this without restarting Eclipse you can execute a BAT file that will restart the ADB server. To do this navigate to your Android installation folder and locate the “platform-tools” folder. Within that folder create an appropriately named BAT file, for example, “restart-adb.bat”. Edit the newly created file in a text editor such as Notepad and add the following two lines:

adb kill-server && adb start-server
pause

Save and close. TO restart ADB simply double-click your bat file and the server will be restarted. A command prompt will appear informing you of what is happening:

Thats it, the ADB has been restarted.

Formatting Credit Card Numbers – Dealing with Webkit Text Input Oddity

27 Apr 2012

Another day, another script added to my library…. I had a credit card text field in one of my Sencha Touch projects that needed to be “dash separated” while the person is typing. Below is my solution to this particular minor challenge. Please remove any other validation in your project as this already features:

  • Removal of all undesired alpha characters and symbols
  • Limited to a maximum of 16 numbers
  • Plays nice when you backspace from the end

Note that you shouldn’t try to correct a number in the middle of the string – if you delete a number the entire string gets re-written for the current string of numbers. Also, the first thing that may come to mind is the HTML 5 “pattern” attribute which accepts a regular expression with which to validate the text field value, however, that would validate as you type, not format the string in the desired manner while the typing is happening. Sencha has its own way of validating text fields which is essentially the same thing but the issue is that it also doesn’t do on-the-fly string formatting.

So here is the function itself, which works perfectly in a normal web-browser (yes, a caveat for android webkit follows):

...
    function do_ccFormat(str){
	var nums = str.substr(0,19).replace(/[^\d]/gi,'');
	var r = nums.match(/(\d){4}/g);
	if (r){	
	    var i=0, nStr = '';
	    for (;i

However, in Android 2.3.6's webkit there is some odd behavior that is a pattern that I'm sure others somewhere have come up against. So the pattern is this: first assume that you are doing some string manipulation on the keyup event, waiting for some criteria to be met at every key stroke before manipulating the string. In the case of my CC formatter its the 5th character that triggers the string re-write. So lets say you type 5 characters such as "12345". When "5" is typed the entire string is replaced with a new one that contains a new character/delimiter - like so: "1234-5". The very next character that you type will not go at the end where the cursor is but before the last character that was entered. So if we enter "6" the string ends up like this: "1234-65". Further, if you hit the backspace key you backup not from the cursor position (which is at the end of the string) but from where the last character was erroneously entered! Weird stuff! This gets worse with every new delimiter that is added to the string.

Upon inspection and some thought, I realize that replacing the value with a formatted value as you type is something that the Android 2.x webkit can't handle when it has to then figure out where the cursor should go. It seems that programatically setting the value does not update the cursor position for the field - it stays where it is. If you pay close attention when all this happens you'll notice that the cursor will quickly jump around.

I then hit upon the idea of blurring the field (thinking to therefore dump whatever erroneous machinations may be at play) and then quickly give focus back to it knowing that the act of giving focus to a field sets the cursor to the end. This works as long as you space out the blur/focus methods with a setTimeout. I spaced them out by 100 milliseconds hoping that the soft keyboard wouldn't flash. This appeared to work well Android 2.3.6 (a Samsung Galaxy S2). The keyboard would just sit there apparently none-the-wiser.

While this did seem to work it turned out to be unpredictable. In Android 2.2 the keyboard would go away and not reappear, sometimes that would happen in 2.3.6, and it does go away in Android 3.

Its unfortunate that this doesn't work in pre-ICS Android - it is what it is. Below is how I implemented it in Sencha Touch 1 - as you can see I apply it on keyup for iOS and ICS for as-you-type formatting. For pre-ICS Android I limit the keyed cc number length to a max of 16 characters and apply CC formater when the CC field is blurred (a length of 19 is needed otherwise since we are adding 3 additional characters in the form of the "-" delimiter).

I should end by saying that this obviously does not include a MOD10 check. I'll toss in my MOD10 checker at a later date as a separate article - it will include the ability to check not only entire cc numbers - which all of the readily available MOD10 checkers do - but it will also allow you to check a CC number for its **type** based on the first four digits. Until then, here's Credit Card String Formatter sample implementation:

...
items:[
  {
    xtype:'textfield',
    name:'cardNumber',
    inputType:'tel',
    maxLength:'19',//allow the 3 dashes needed to format the string to be included
    listeners:{
	keyup:function(o,e){
            if (Ext.is.iOS || (Ext.is.Android && Ext.is.AndroidVersion > 3)){
	        o.setValue(do_ccFormat(o.getValue()));
            } else { // assume old android
                o.setValue(o.setValue().substr(0,16));
            }
	},
        blur:function(o,e){
            if (Ext.is.Android && Ext.is.AndroidVersion < 3){
               o.setValue(o.setValue().substr(0,16));
               o.setValue(do_ccFormat(o.getValue()));
            }
        }
    }
  }
]
...

Solving “The connection to the server was unsuccessful” Error in Android/PhoneGap

10 Apr 2012

At some point in time you will always have to update your dev environment – and inevitably when doing so you will find that you can’t compile your apps any more for any sort of a number of reasons – doesn’t matter if its iOS or Android (though I find its much, much more common on iOS). Well, today I’ve updated my Android SDK since I’d like for the first time ever to be able to use the AVD as Google has improved performance in that area. However, upon compiling one of my apps I have run into this error:

...
04-10 10:46:13.672: I/System.out(4057): onReceivedError: Error code=-6 Description=The connection to the server was unsuccessful. URL=file:///android_asset/www/index.html
...

This can be solved by adding a line to your main activity.java file:

...
super.setIntegerProperty("loadUrlTimeoutValue", 7000);
...

The timeout value itself is arbitrary, here I have it at 7 seconds. Adding this one line above the super.loadUrl resolves the “Connection to the server was unsuccessful” error.

Also, check to make sure that any remote scripts such as those being delivered to the app from a server are accessible. Sometimes I forget to remove the remote debugger from a project and find that this error will appear because the script cannot be downloaded – in that case you see the error message appear while the app loads behind it. So, check your script tags for remotely loading scripts and remove any hooks to remote debuggers/testing servers. You should also download copies of javascript libraries and keep them within your app to remove or at least reduce the chances of this error appearing.