Friday, November 29, 2013

How to Get the Audio File of the Audio Recorder Intent in Android

When you need to record audio on your android application, you have two options: 1.) To implement your own audio recorder and 2.) To use the default default audio recorder of the android device. For some cases, it is more convenient to use the second option because we would no longer need to do additional coding just to accomplish our goal. So to start the audio recorder, we use an intent:
1:          Intent intent = new Intent(MediaStore.Audio.Media.RECORD_SOUND_ACTION);  
2:          startActivityForResult(intent, RECORD_SOUND);  
Please note that the RECORD_SOUND variable is just any integer that serves as the request code for our Audio Record activity so we would know if the result we receive is from that activity.  We use it on this section of our MainActivity's code:
1:       protected void onActivityResult(int requestCode, int resultCode, Intent data) {  
2:            switch(requestCode) {  
3:                 case RECORD_SOUND:  
4:                      /*  
5:                       * get the recorded file's path if resultCode is ok  
6:                       */  
7:                      break;  
8:                 default:  
9:                      super.onActivityResult(requestCode, resultCode, data);  
10:                      break;  
11:            }  
12:       }  

To get the path of the recorded audio most guides use this code:
1:  data.getData().getPath()  
However, when I tried using the value of the path returned by that method, I noticed that the file cannot be accessed. After a bit of digging around, I saw this method to get the actual path:
1:       private String getAudioFileRealPath(Intent data) {  
2:            String realPath = "";  
3:            String[] filePathColumn = { MediaStore.Images.Media.DATA };  
4:            Cursor cursor = getContentResolver().query(data.getData(), filePathColumn, null, null, null);   
5:            if(cursor.moveToFirst()){  
6:              int columnIndex = cursor.getColumnIndex(filePathColumn[0]);  
7:              realPath = cursor.getString(columnIndex);  
8:            }  
9:            cursor.close();  
10:            return realPath;  
11:       }  
Here is a comparison of the paths obtained:

The full source code for this tutorial can be found here

Thursday, November 28, 2013

Caching Remote Images in Titanium Mobile

Previously, I demonstrated how to use Universal Image Loader for caching remote images on an android application. For Titanium Mobile Applications, I will show a method to achieve the same effect. Please note however that you may need to modify the code to handle the cleanup of any unused downloaded files.

Here is the code for the caching method:
1:  function cacheImageAndLoad(url, imageView){  
2:       var fileName = url.substring(url.lastIndexOf('/') + 1);  
3:       var fileCopy = Ti.Filesystem.getFile(Ti.Filesystem.applicationDataDirectory, fileName);  
4:       if (!fileCopy.exists()) {  
5:            var xhr = Ti.Network.createHTTPClient({  
6:                 onload : function(e) {  
7:                      fileCopy.write(xhr.responseData);  
8:                      imageView.image = fileCopy.nativePath;  
9:                 },  
10:                 onerror : function(e) {  
11:                      /*  
12:                       * show default image  
13:                       */  
14:                 },  
15:                 timeout : 20000  
16:            });  
17:            xhr.open('GET', url);  
18:            xhr.send();  
19:       }  
20:       else {  
21:            imageView.image = fileCopy.nativePath;  
22:       }  
23:  }  

Check the demo application code here

Tuesday, November 26, 2013

Access Cache file on Universal Image Loader

Sometimes, when using the Universal Image Loader library, there comes a time where the loader takes a while to verify whether the remote image has been already loaded in your cache. To load the cache file directly, you can use the following method to check whether a local copy of the remote file has already been made:

 File file = imageLoader.getDiscCache().get(url);  
 if (!file.exists()) {  
      DisplayImageOptions options = new DisplayImageOptions.Builder()  
      .cacheOnDisc()  
      .build();  
      imageLoader.displayImage(url, imageView, options);  
 }  
 else {  
      imageView.setImageURI(Uri.parse(file.getAbsolutePath()));  
 }  


Universal Image Loader Tutorial

When using images for an android application. You often encounter a situation where you need to display an image located in a remote server. Since displaying images directly on the views would have considerable impact on the application, we need to cache them first before displaying them. To assist me in this scenarios, I use the Universal Image Loader.

To start using this library, you need to include the universal-image-loader-x.y.z.jar file into your project.

Set the permissions on the application manifest:

1:    <uses-permission android:name="android.permission.INTERNET" />  
2:    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />  

Create a subclass of the Application class where you will initialize the image loader configuration:
1:  public class UILDemoApplication extends Application {  
2:       @Override  
3:       public void onCreate() {  
4:            super.onCreate();  
5:            ImageLoaderConfiguration config = new ImageLoaderConfiguration.Builder(getApplicationContext())  
6:            .threadPriority(Thread.NORM_PRIORITY - 2)  
7:            .denyCacheImageMultipleSizesInMemory()  
8:            .discCacheFileNameGenerator(new Md5FileNameGenerator())  
9:            .tasksProcessingOrder(QueueProcessingType.LIFO)  
10:            .enableLogging()   
11:            .build();  
12:            ImageLoader.getInstance().init(config);  
13:       }  
14:  }  

Update your application manifest to set the name of the Application tag into UILDemoApplication the class name:
1:  <application  
2:      android:name=".UILDemoApplication"  
3:      android:allowBackup="true"  
4:      android:icon="@drawable/ic_launcher"  
5:      android:label="@string/app_name"  
6:      android:theme="@style/AppTheme" >  

To use the image loader, first get an instance to the image loader class. In my sample application, it is located on the ImageListAdapter that I created:
1:       private Context context;  
2:       private ImageLoader imageLoader;  
3:       public ImageListAdapter(Context context) {  
4:            this.context = context;  
5:            imageLoader = ImageLoader.getInstance();  
6:       }  

For loading images on your image view, you can use check on the sample code below
1:            DisplayImageOptions options = new DisplayImageOptions.Builder()  
2:            .cacheOnDisc()  
3:            .build();  
4:            imageLoader.displayImage(urls[position], vh.imageView, options);  

As you can see from the code above, I specified some options for displaying the image. I enabled caching the image on the disc so that we won't need to download the image everytime we need to display it. It is also possible to display the image without any options by just calling:
1:  imageLoader.displayImage(urls[position], vh.imageView);  

The full source code for this tutorial can be found here.

RoboSpice Spring

Robospice Spring Android module is a library that you can use when you need to handle restful network communication on your application. Recently, it has been highly advised to use a dependency manager to add this library to your projects. Since the official documentations already contain plenty of guides for that, I will just skip that part. For this tutorial, just make sure that you have the needed jar files. Here are the list of jars:

robospice-cache-x.y.z.jar
robospice-x.y.z.jar
commons-io-x.y.z.jar
commons-lang3-x.y.z.jar
spring-android-core-x.y.z.jar
spring-android-rest-template-x.y.z.jar
robospice-spring-android-x.y.z.jar

These optional libraries are also useful:

jackson-core-asl-x.y.z.jar
jackson-mapper-asl-x.y.z.jar 
jackson-databind-x.y.z.jar
gson-x.y.z.jar
simple-xml-x.y.z.jar

Update the application manifest by adding these permissions:
1:    <uses-permission android:name="android.permission.INTERNET"/>  
2:    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>  
3:    <uses-permission android:name="android.permission.ACCESS_WIFI_STATE"/>  

Also add the JacksonSpringAndroidSpiceService within the application section of the manifest:
1:  <service android:name="com.octo.android.robospice.JacksonSpringAndroidSpiceService" android:exported="false" />  

For the WebService, we will use the OpenWeatherMap forecast api samples. To handle the api response data, we need to prepare the necessary classes but first we need to take a look at the json object from the server.


As you can see, each list item consists of several fields. Some fields consist of strings while others are composed of json objects or json array. For the json objects like the temp property, we prepare an object to handle its data:
1:  @JsonIgnoreProperties(ignoreUnknown = true)  
2:  public class Temp {  
3:       private String day;  
4:       private String min;  
5:       private String max;  
6:       private String night;  
7:       private String eve;  
8:       private String morn;  
9:       public String getDay() {  
10:            return day;  
11:       }  
12:       public void setDay(String day) {  
13:            this.day = day;  
14:       }  
15:       public String getMin() {  
16:            return min;  
17:       }  
18:       public void setMin(String min) {  
19:            this.min = min;  
20:       }  
21:       public String getMax() {  
22:            return max;  
23:       }  
24:       public void setMax(String max) {  
25:            this.max = max;  
26:       }  
27:       public String getNight() {  
28:            return night;  
29:       }  
30:       public void setNight(String night) {  
31:            this.night = night;  
32:       }  
33:       public String getEve() {  
34:            return eve;  
35:       }  
36:       public void setEve(String eve) {  
37:            this.eve = eve;  
38:       }  
39:       public String getMorn() {  
40:            return morn;  
41:       }  
42:       public void setMorn(String morn) {  
43:            this.morn = morn;  
44:       }  
45:  }  

For an array type (just like the weather list) we do declare it like this:
1:       private List<Weather> weather;  

For our request to the webservice, we prepare the following request object:
1:  public class ForecastListRequest extends SpringAndroidSpiceRequest<ForecastList> {  
2:       public ForecastListRequest() {  
3:            super(ForecastList.class);  
4:       }  
5:       @Override  
6:       public ForecastList loadDataFromNetwork() throws Exception {  
7:            Uri.Builder builder = Uri.parse("http://api.openweathermap.org/data/2.5/forecast/daily?lat=35&lon=139&cnt=7&mode=json").buildUpon();  
8:            return getRestTemplate().getForObject(builder.build().toString(), ForecastList.class);  
9:       }  
10:  }  

After preparing the objects, we need to instantiate our spiceManager in our activity to be able to use it:

1:  private SpiceManager spiceManager = new SpiceManager(JacksonSpringAndroidSpiceService.class);  

Also we need to start it on the onStart method of the activity before using it:
1:       @Override  
2:       protected void onStart() {  
3:            super.onStart();  
4:            spiceManager.start(this);  
5:       }  

And stop the spiceManager when the activity stops:
1:       @Override  
2:       protected void onStop() {  
3:            spiceManager.shouldStop();  
4:            super.onStop();  
5:       }  

In our onCreate method, we execute the request like this:
1:  ForecastListRequest request = new ForecastListRequest();  
2:            spiceManager.execute(request, new RequestListener<ForecastList>() {  
3:                 @Override  
4:                 public void onRequestFailure(SpiceException arg0) {  
5:                      Log.i("ForecastListRequest", "failed");  
6:                 }  
7:                 @Override  
8:                 public void onRequestSuccess(ForecastList arg0) {  
9:                      Log.i("ForecastListRequest", "success!");  
10:                      List<Forecast> list = arg0.getList();  
11:                      for (Forecast forecast : list) {  
12:                           Log.i("ForecastListRequest", "dt=" + forecast.getDt());  
13:                      }  
14:                 }  
15:            });  

The full source code for this tutorial can be downloaded here

Monday, November 25, 2013

Using Java Enum As An Alternative to Bit Flags

Recently, I needed to use bit flags as parameter to a method to determine its output. I noticed while doing a bit of research online that most people suggest using EnumSet instead of bit flags as a parameter. Normally,  I use the bit flag like this:

1:  public class SampleUtil {  
2:       public static final int FLAG_1 = 1 << 0;  
3:       public static final int FLAG_2 = 1 << 1;  
4:       public static final int FLAG_3 = 1 << 2;  
5:       private static String processString1(String input) {  
6:            return input + "process1";  
7:       }  
8:       private static String processString2(String input) {  
9:            return input + "process2";  
10:      }  
11:      private static String processString3(String input) {  
12:           return input + "process3";  
13:      }  
14:      public static List<String> processInput(String input, int flags){  
15:            List<String> output = new ArrayList<String>();  
16:            if ((flags & FLAG_1) == FLAG_1) {  
17:                 output.add(processString1(input));  
18:            }  
19:            if ((flags & FLAG_2) == FLAG_2) {  
20:                 output.add(processString2(input));  
21:            }  
22:            if ((flags & FLAG_3) == FLAG_3) {  
23:                 output.add(processString3(input));  
24:            }  
25:            return output;  
26:       }  
27:  }  

For every flag set, I perform a method on an input and add it to the results. Works well but maybe things could be better.. so I decided to take a look at using enums. Taking another look at the docs, I remembered that enums are much more powerful and versatile than bit flags.

Since enum is also a class, I decided to exploit this property. One thing I noticed with the methods used for processing the string is that they all have the same input and output type. Another thing is that each one is tied to a certain flag exclusively. Because of this, I made an interface that represents all these methods.
1:  public interface IStringProcessor {  
2:       String processString(String input);  
3:  }  

Then, I modified the constructor to add a parameter for the enum:
1:       private IStringProcessor processor;  
2:       ProcessFlag(IStringProcessor processor) {  
3:            this.processor = processor;  
4:       }  

I also added a method to my enum class so I can use the processor passed on the constructor of the enum.
1:       public String applyMethod(String input) {  
2:            return processor.processString(input);  
3:       }  

Then I initialized the enums:
1:       FLAG_1(new IStringProcessor(){  
2:            @Override  
3:            public String processString(String input) {  
4:                 return input + "process1";  
5:            }  
6:       }),  
7:       FLAG_2(new IStringProcessor(){  
8:            @Override  
9:            public String processString(String input) {  
10:                 return input + "process2";  
11:            }  
12:       }),  
13:       FLAG_3(new IStringProcessor(){  
14:            @Override  
15:            public String processString(String input) {  
16:                 return input + "process3";  
17:            }  
18:       });  

To use enumset as a parameter, I modified my "processInput" method and used the enum type for processing my input string:
1:       public static List<String> processInput(String input, EnumSet<ProcessFlag> flags){  
2:            List<String> output = new ArrayList<String>();  
3:            Iterator<ProcessFlag> iterator = flags.iterator();  
4:            while (iterator.hasNext()) {  
5:                 ProcessFlag pFlag = iterator.next();  
6:                 output.add(pFlag.applyMethod(input));  
7:            }  
8:            return output;  
9:       }  

Here is a short code to demonstrate how to use the "processInput" method:
1:       public static void main(String[] args) {  
2:            EnumSet<ProcessFlag> flags = EnumSet.of(ProcessFlag.FLAG_1, ProcessFlag.FLAG_2);  
3:            List<String> strings = SampleUtil.processInput("Hello", flags);  
4:            for (String s : strings) {  
5:                 System.out.println(s);  
6:            }  
7:       }  

A complete source for this demo can be downloaded from here

Monday, July 29, 2013

Starting With ActionBarSherlock

ActionBarSherlock is a library that extends the android support library to enable applications to use the action bar on devices with lower versions of the android os.

To follow this guide, you must download the ActionBarSherlock library from here.

After you have extracted the contents of the source file archive (the name of the file I downloaded is JakeWharton-ActionBarSherlock-4.4.0-0-g4a79d53.zip which, I assume, is the latest version), you must import the source file to create an android library project.

Select Import->Existing Android Code Into Workspace and navigate to the folder where you extracted the source archive. Select the folder named actionbarsherlock.


Check if the project is set as a library by viewing the project Properties->Select Android and check on the right part of properties window if the following is checked:

Create a new android project that you will use for testing the actionbarsherlock library. After the project is created, you need to reference the action bar library by viewing the Properties -> Android window again. Click add, and select the actionbarsherlock project that you imported earlier.

Please note that in my screenshot, I renamed the actionbarsherlock folder into abs.

To be able to use the action bar, your activity must extend the SherlockActivity class:

1:  package org.kaithe.android;  
2:  import com.actionbarsherlock.app.SherlockActivity;  
3:  import android.os.Bundle;  
4:  public class MainActivity extends SherlockActivity {  
5:       @Override  
6:       protected void onCreate(Bundle savedInstanceState) {  
7:            super.onCreate(savedInstanceState);  
8:            setContentView(R.layout.activity_main);  
9:       }  
10:  }  

From this point, you can already run your application. However, it will just look plain since we still haven't done any customisations on the action bar.


To test the action bar, we will add some items in it. Override the onCreateOptionsMenu method from the SherlockActivity class.
1:       @Override  
2:       public boolean onCreateOptionsMenu(Menu menu) {  
3:      menu.add("Save")  
4:        .setIcon(R.drawable.ic_compose)  
5:        .setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM);  
6:      menu.add("Search")  
7:        .setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM | MenuItem.SHOW_AS_ACTION_WITH_TEXT);  
8:      menu.add("Refresh")  
9:        .setIcon(R.drawable.ic_refresh)  
10:        .setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM | MenuItem.SHOW_AS_ACTION_WITH_TEXT);  
11:      return true;  
12:       }  

In here, we created 3 menu on the action bar. Running the application, this is what our action bar will look like:


The action bar sherlock library source that I used can be found in here
The full action bar sample application source can be obtained here

Thursday, June 13, 2013

Camera Overlays for Titanium Mobile Android

To add overlays to the Titanium Mobile camera screen, you need to set the overlay property of your CameraOptionsType:

1:  Titanium.Media.showCamera({  
2:   success : function(e) {},  
3:   error : function(e) {},  
4:   cancel : function(e) {},  
5:   overlay : Ti.UI.createView({  
6:    backgroundImage : '/crosshair.png',  
7:    width : '200dp',  
8:    height : '200dp'  
9:   })  
10:  })  

While that step looks simple enough, you might still encounter some unexpected errors like this: (Unable to find explicit activity class... TiCameraActivity)


From the error, we can see that the activity class for TiCameraActivity was not defined in the Android manifest. Normally, that entry is supposed to be added automatically to the generated manifest file but what happened here is that its missing. This happened because I am using a custom manifest file. I created the custom manifest before I added the camera code which is why the camera activity definition is missing from the manifest. To fix this, simply add the code to your custom manifest file in between the <application></application> tags:

1:  <activity   
2:            android:name="ti.modules.titanium.media.TiCameraActivity"  
3:            android:configChanges="keyboardHidden|orientation"  
4:            android:theme="@android:style/Theme.Translucent.NoTitleBar.Fullscreen" />  

Also note that while this fixes the crash problem, you will also face another weird problem with the overlay on android:
You can see that the overlay's orientation is converted to landscape, even though the image I used is in portrait mode. But since that problem is simple enough to solve, I'll just leave it as is..

You can get the source code for this application in here

Displaying Images Taken from Titanium Mobile showCamera Method

While the api documentation for the Ti.Media.showCamera method does a pretty good job in demonstrating how to call the camera application, it does not show how the use or display the image that was captured by the camera. So after spending some time with it, I was able to come up with this solution to display my image.

First, I created a wrapper that will contain my picture:

1:  var imageWrapper = Ti.UI.createView({  
2:       backgroundColor : 'red',  
3:       width : '300dp',  
4:       height : '385dp',  
5:       top : '65dp'  
6:  });  
7:  win.add(imageWrapper);  

Then, on the success callback of the CameraOptionsType, I created an image view that will contain the image data from the native camera application:

1:  var image = event.media;   
2:  tempImage = Ti.UI.createImageView({  
3:   image : image,  
4:   width : '385dp',  
5:   height : '300dp'  
6:  });  

From what I have observed, the images taken on the android device are not properly oriented (maybe its the same on ios), so I rotate the images before adding them on the wrapper I prepared earlier:

1:  var rotation = Ti.UI.create2DMatrix({ rotate : -270 });  
2:  tempImage.transform = rotation;  
3:  imageWrapper.add(tempImage);  

To test the whole application, get the full source code here

Android MapsV2 Module Sample Code in Titanium Mobile Alloy

With the introduction of SDK 3.0, a new framework called Alloy had been integrated with Titanium. This framework uses model-view-controller architecture to break down your application code. While it is fairly simple to learn the new framework, I encountered a bit of slowdown when trying to use the new Google Maps Android v2 module in it. To help save a lot of time, I'll demonstrate how I used the  map module on the new framework.

First, you need to download the map module from here. After you have downloaded the zip file, you need to put the extracted contents on the root folder of your application.


You can also put the module in the Titanium SDK Home Directory (but for me, I prefer to use the application folder).

After placing the module on the proper folder, you need to edit the tiapp.xml file on your project root. Find the <modules/> tag and update it like below:
1:    <modules>  
2:         <module platform="android" version="2.1.0">ti.map</module>  
3:    </modules>  

Find the <android xmlns:android="http://schemas.android.com/apk/res/android"/> tag and update it as well:
1:  <android xmlns:android="http://schemas.android.com/apk/res/android">  
2:      <manifest>  
3:        <!-- Allows the API to download data from Google Map servers -->  
4:        <uses-permission android:name="android.permission.INTERNET"/>  
5:        <!-- Allows the API to cache data -->  
6:        <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>  
7:        <!-- Use GPS for device location -->  
8:        <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>  
9:        <!-- Use Wi-Fi or mobile connection for device location -->  
10:        <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>  
11:        <!-- Allows the API to access Google web-based services -->  
12:        <uses-permission android:name="com.google.android.providers.gsf.permission.READ_GSERVICES"/>  
13:        <!-- Specify OpenGL ES 2.0 as a requirement -->  
14:        <uses-feature android:glEsVersion="0x00020000" android:required="true"/>  
15:        <!-- Replace com.domain.appid with your application ID -->  
16:        <uses-permission android:name="<com.domain.appid>.permission.MAPS_RECEIVE"/>  
17:        <permission android:name="<com.domain.appid>.permission.MAPS_RECEIVE"  
18:          android:protectionLevel="signature"/>  
19:        <application>  
20:          <!-- Replace "PASTE YOUR GOOGLE MAPS API KEY HERE" with the Google API key you obtained -->  
21:          <meta-data android:name="com.google.android.maps.v2.API_KEY"  
22:            android:value="PASTE YOUR GOOGLE MAPS API KEY HERE"/>  
23:        </application>  
24:      </manifest>  
25:    </android>  

Remember to set your api key on the android:value property of the meta-data tag on the manifest section of your tiapp.xml file. Also, change the <com.domain.appid> strings on that same section with your application id found between the <id></id> tags in the tiapp.xml file.

An alloy application framework code is divided into four parts. Each part can be located in its corresponding folder under the app directory. For my sample application, I have no need for a model so you can see that it's folder is empty.


Since all alloy application start with the index, you can see the controllers, views, and styles had been created. I don't need customise the view so I just removed the sample code from it:

1:  <Alloy>  
2:       <Window class="container">  
3:       </Window>  
4:  </Alloy>  


To instantiate the module, just use the require method. In my sample application, I placed it in the index controller. The file can be found inside the app/controllers/ directory. The code for my index.js file is as follows:

1:  var MapModule = require('ti.map');  
2:  var mapview = MapModule.createView({  
3:       mapType : MapModule.NORMAL_TYPE,  
4:       region: {  
5:            latitude:33.74511,   
6:            longitude:-84.38993,  
7:      latitudeDelta:0.01,   
8:      longitudeDelta:0.01  
9:    },  
10:    top : 0,  
11:    left : 0,  
12:    right : 0,  
13:    bottom : 0,  
14:    animate:true,  
15:    regionFit:true  
16:  });  
17:  $.index.add(mapview);  
18:  $.index.open();  

Just adding the code above on the index controller will already add the MapView on the application window.  If you need more info on the MapView, just consult the API docs.

To see the full source of my sample application go here

MapView Transparency Bug on Titanium Android

While using the new MapView module for android, I noticed that the view becomes blank when it is animated. Even when I tried to refresh the view, the map would remain to be invisible (or seems to be located at the background).

At first, I thought it was the drawer menu widget that I was using. However, as I looked further, I was able to confirm that any animation that moves the MapView on the screen causes it to become invisible (like my sample below):

View code:
1:  <Alloy>  
2:       <Window class="container">  
3:            <View id="mainwindow" top="0" left="0" right="0" bottom="0" backgroundColor="white" onClick="doClick">  
4:            </View>  
5:       </Window>  
6:  </Alloy>  

Controller code:
1:  var MapModule = require('ti.map');  
2:  var mapview = MapModule.createView({  
3:       mapType : MapModule.NORMAL_TYPE,  
4:       region: {  
5:            latitude:33.74511,   
6:            longitude:-84.38993,  
7:      latitudeDelta:0.01,   
8:      longitudeDelta:0.01  
9:    },  
10:    top : '50dp',  
11:    left : 0,  
12:    right : 0,  
13:    bottom : 0,  
14:    animate:true,  
15:    regionFit:true  
16:  });  
17:  $.mainwindow.add(mapview);  
18:  function doClick(e) {   
19:    $.mainwindow.animate({  
20:         left : '300dp',  
21:         top : 0,  
22:         right : 0,  
23:         bottom : 0  
24:    });  
25:  }  
26:  $.index.open();  

To check if the problem is rooted at the native android sdk, I created a similar scenario on a native android application. When I was not able to encounter the same problem,  I then tried to find a workaround for this bug.

After a lot of searching, I finally found out that using hardware acceleration on the application would help in bringing back the MapView. So, going to the Android manifest, you need to find the application tag and add the property to enable hardware acceleration on your application:

1:  <application android:icon="@drawable/appicon"  
2:            android:label="sample" android:name="SampleApplication"  
3:            android:debuggable="false"  
4:            android:hardwareAccelerated="true">  

Please note that using this solution, the MapView may still disappear a bit while the view is animating, but it comes back again after the animation finishes.

Thursday, May 23, 2013

TextField Focus Bug on Titanium Mobile Android

When using the TextField inside a TableView, I noticed that it would lose focus immediately after being selected but the keyboard remains shown. If you type anything on the keyboard, nothing gets displayed on the TextField. After a bit of tinkering, I was able to replicate this behavior with a simple code:
1:       var win1 = Ti.UI.createWindow({  
2:            navBarHidden : true,  
3:            top : 0,  
4:            left : 0,  
5:            right : 0,  
6:            bottom : 0  
7:       });  
8:       var subView = Ti.UI.createView({  
9:            backgroundColor : '#ffffff',  
10:            top : 0,  
11:            left : 0,  
12:            right : 0,  
13:            bottom : 0  
14:       });  
15:       win1.add(subView);  
16:       var _data = [];  
17:       var tableViewRow = Ti.UI.createTableViewRow({  
18:            height : '45dp',  
19:            left : 0,  
20:            right : 0  
21:       });  
22:       var textField = Ti.UI.createTextField({  
23:            top : '5dp',  
24:            left : '20dp',  
25:            right : '20dp',  
26:            height : '35dp'  
27:       });  
28:       tableViewRow.add(textField);  
29:       _data.push(tableViewRow);  
30:       var tableView = Ti.UI.createTableView({  
31:            backgroundColor : '#c0c0c0',  
32:            data : _data,  
33:            top : '10dp',  
34:            left : '20dp',  
35:            right : '20dp',  
36:            bottom : '10dp'  
37:       });  
38:       subView.add(tableView);  
39:       win1.open();  

After searching through the code, I was able to determine that the auto height adjustment is the cause for the problem. To fix the bug, you need to set the height property of the TableView to a fixed value:

1:       var tableView = Ti.UI.createTableView({  
2:            backgroundColor : '#c0c0c0',  
3:            data : _data,  
4:            top : '10dp',  
5:            left : '20dp',  
6:            right : '20dp',  
7:            height : '380dp'  
8:       });  
9:       subView.add(tableView);  

To view the complete source check here

As an update to this solution, I found out that while setting the height of the TableView fixes the focus bug, it also affects the view in a way such that, some TextFields near the bottom of the table becomes obstructed by the android keyboard whenever they are active:


In the picture above, I selected the row labeled TextField 30 but as you can see, it is not visible since the keyboard is obstructing it.

Since I cannot find a suitable fix with this problem on the TableView, I decided it is time to use the ScrollView instead:

From what I have tested, this fixes the focus bug on the TextField, while also having similar display to the TableView.

Complete source for the second application is here

Friday, May 10, 2013

Loading Images from Application Data Directory Vs. Assets Directory on Titanium Mobile Android

While working on lists with images on an application, I noticed something weird: loading images  that I cached (created a copy on the local application directory) sometimes fails and blank views are instead shown on the screen.

At first I thought that the downloader is causing the memory leak since I don't set it to null after downloading the images. However, after setting it null (and the other objects I use for copying the file), nothing changed and still the views become blank after some use. After a lot of searching and trying different ways to load the images, I found out that when I load images from the assets directory, they do not disappear.

So to verify if my observation is correct, I performed a test. I created two separate windows with the same UI layout and objects, but one window is loading from the assets directory and one would load from the application data directory. Here is the comparison of the two views:



The picture on the left is the list loading images from the application data directory and the one on the right loads images from the assets directory. As you can see, some of the images on the left picture disappear after the list is scrolled several times.

In titanium all files under the resources directory are stored in the assets folder. So if the images you need to display will be used for a long time or is a permanent part of the application, I would suggest that you place it in the assets directory. If you need to display cached images, it would be better if you use the WebView just like what I previously did.

Full source code for my test application can be downloaded from here.

Thursday, May 9, 2013

Customise Basic Push Notifications on Urban Airship Android

For this tutorial, I modified the sample application code inside the Urban Airship package. To be able to follow, you must have the Urban Airship Push Sample application working on your side (have the urbanairship.properties file ready) and have the android-support-v4.jar properly setup (used for building the custom notification for the app).

From the sample app, you will notice that the basic push notification layout looks exactly the same for all your push alerts. It is sufficient if you want to make all your notifications standard but sometimes, you want to make differences for your alerts to help the user have a better idea of the type of message received (for example some notifications can be considered more important than others).

To start, you need to modify the MyApplication class. Previously, the code to customize the layout is this block:

1:  CustomPushNotificationBuilder nb = new CustomPushNotificationBuilder();  
2:  nb.statusBarIconDrawableId = R.drawable.icon_small;//custom status bar icon  
3:  nb.layout = R.layout.notification;  
4:  nb.layoutIconDrawableId = R.drawable.icon;//custom layout icon  
5:  nb.layoutIconId = R.id.icon;  
6:  nb.layoutSubjectId = R.id.subject;  
7:  nb.layoutMessageId = R.id.message;  
8:  PushManager.shared().setNotificationBuilder(nb);  

You can replace the code in that block with:

1:  BasicPushNotificationBuilder nb = new BasicPushNotificationBuilder() {  
2:       @Override  
3:       public Notification buildNotification(String alert,   
4:            Map<String, String> extras)   
5:       {  
6:            return null;  
7:       }  
8:  };  
9:  PushManager.shared().setNotificationBuilder(nb);  

The code above will prevent the push manager from handling the creation of the notification.

Going back to the MyApplication class, since we already have the IntentReceiver class as the handler for the intents from the push manager,

1:  PushManager.shared().setIntentReceiver(IntentReceiver.class);  

we can go to this class and start modifying it to handle the notification creation.

First, add a NotificationManager class instance to handle the sending of our custom notification. On my sample application, I placed it within the onReceive method:

1:      if (notificationManager == null) {  
2:           notificationManager = (NotificationManager)context.getSystemService(Context.NOTIFICATION_SERVICE);  

Then, find the block that handles the action for a push receive. On the push sample code, it is in here:

1:  if (action.equals(PushManager.ACTION_PUSH_RECEIVED)) {  
2:  }  

Add the code to create and send the Notification: (for this sample application, I am expecting the extra data value from the push to appear on this form: notif_type,notif_id,title,message and with key notif_data )

1:  if (action.equals(PushManager.ACTION_PUSH_RECEIVED)) {  
2:       String notif_test = intent.getStringExtra("notif_data");  
3:       if (notif_test != null) {  
4:             String[] notif_data = notif_test.split(",");  
5:             Uri ringToneUri = RingtoneManager.getDefaultUri((notif_data[0].equalsIgnoreCase("0")) ? RingtoneManager.TYPE_NOTIFICATION : RingtoneManager.TYPE_RINGTONE);  
6:             int notif_icon = (notif_data[0].equalsIgnoreCase("0")) ? android.R.drawable.ic_dialog_alert : android.R.drawable.ic_dialog_info;  
7:             NotificationCompat.Builder mBuilder = new NotificationCompat.Builder(context)  
8:             .setSound(ringToneUri)  
9:             .setSmallIcon(notif_icon)  
10:             .setContentTitle(notif_data[2])  
11:                      .setContentText(notif_data[3])  
12:                      .setAutoCancel(true)  
13:                      .setStyle(new NotificationCompat.InboxStyle());  
14:             Notification notification = mBuilder.build();  
15:             notificationManager.notify(Integer.parseInt(notif_data[1]), notification);  
16:       }  
17:  }   

When sending notifications, you can set the first part of the extra value (notif_type) to 0 or any number to change the icon and the tone played for the notification.

To view the complete source for my test application go here.

Friday, March 22, 2013

Smooth Scrolling List/TableView for Titanium Android

For those who have been using the Titanium TableView UI to render lists, you may have noticed that there is a significant lag on the scroll animation when the number of list items are increased. Most of the time, if there are images on the row, the list becomes choppy and sometimes the application crashes (especially on android).  Since most of the solutions I found only adds minimal improvement on the performance, I just accepted this issue as unresolvable until a titanium sdk update handles this.

However, after using different titanium views for a while, I accidentally discovered a viable alternative to the TableView. After seeing WebViews render lists containing a lot of items with ease, I realized that I can use it as a substitute for my TableViews.

To create a "ListView" type of UI on the WebView, I used the html Table on the code like below: (Please note that I have used Mustache for rendering the data on the html template)

1:  <table border="0" style="width:100%;">  
2:                 {{#table_rows}}  
3:                 <tr onclick="Ti.App.fireEvent('app:handleRowSelect', { index : '{{row_index}}' })">  
4:                      <td>  
5:                           <img src="{{{image_url}}}" style="width:320px; height:240px; position:relative; left:10px; top:5px;"/>  
6:                      </td>  
7:                 </tr>  
8:                 {{/table_rows}}  
9:  </table>   

As you can seen on the code, I just used styles to make the rows look like a list on a TableView.  You can also see that I am firing an event whenever a row is clicked. I'll explain later how it is used.. Here is what the views look like when running on Android tablet:



You can make them look almost exactly the same so the user wouldn't notice that you are indeed using only a WebView instead of a ListView on android.

To simulate the TableView "click" event handler, you must declare an event handler on your application to capture the event fired from your html:

1:  function handleRowSelect(e) {  
2:   alert('You have selected the row with index ' + e.index);  
3:  }  
4:    
5:  Ti.App.addEventListener('app:handleRowSelect', handleRowSelect);  

Whenever the app:handleRowSelect is fired from the HTML, the handleRowSelect function will be called and the event data will be passed as parameters to this function. From the HTML code above, the   Event is fired with an object that contains the index of the row: Ti.App.fireEvent('app:handleRowSelect', { index : '{{row_index}}' }) and from this, you will be able to perform any operation on the data corresponding to the row selected.

You can try and see for yourself the huge performance improvement from using the WebView for large lists on android from here

Thursday, March 7, 2013

Gap Appears on HTML div When Using Titanium Webview on Android



I encountered this irritating bug when using a WebView on my application and I was trying to make a div that has a fixed position on the page. At first I thought I set the styles wrong but a further investigation confirms that a gap is really being generated when displaying the div on the WebView.

After looking a bit on my code I found out that Hardware Acceleration affects the WebView and causes this bug to appear. On my application, the setting (for hardware acceleration) can be found on the /platform/android/AndroidManifest.xml file.

Here is the part where the property is set:

1:  <application android:icon="@drawable/appicon"  
2:            android:hardwareAccelerated="true"   
3:            android:label="AndroidWebViewElemGaps" android:name="AndroidwebviewelemgapsApplication"  
4:            android:debuggable="false">  

Removing this setting fixes the WebView but if you really need hardware acceleration for your app, you are out of luck for the mean time. It's worth noting though that not all devices are affected by this bug. Here is the app running on smartphone without any problems:



Source code for my test project can be found in here.

Monday, February 25, 2013

Titanium Mobile Opening New Window Closes the Application on Android

I encountered this error while testing the application on someone else's Android device. I wondered why the application suddenly crashes whenever I open something on a new window. At first I thought it has something to do with memory allocation errors, but when I checked the logs, it shows nothing. Then finally, when I can't see anything wrong with the code, I checked the device and look for the differences of the device from the one I was using. Finally I saw this checkbox under android Settings -> Developer Options:


Apparently, enabling this setting closes the main activity of the android application even if it is still needed. To prevent this from happening, you need to change the initialization of the new window a bit.

In Titanium Android, when creating a window, setting the property navBarHidden to true will often create a new activity like the code below:

1:  var newWin = Ti.UI.createWindow({  
2:            navBarHidden : true,  
3:            backgroundColor : 'red',  
4:            top : 0,  
5:            left : 0,  
6:            right : 0,  
7:            bottom : 0  
8:       });  

To prevent a new activity from being called, just use the property modal and set it to true like the code below:

1:  var newWin = Ti.UI.createWindow({  
2:            navBarHidden : true,  
3:            backgroundColor : 'blue',  
4:            top : 0,  
5:            left : 0,  
6:            right : 0,  
7:            bottom : 0,  
8:            modal : true  
9:       });  

The full source code for the demo can be see here

Thursday, February 21, 2013

Custom Font on Local Html for Titanium Mobile SDK WebView for Android

While trying to load a locally generated html on the android webview, I noticed that it was not able to render the text content with the custom font face I was using. After some searching, I found out that this issue is not only present on titanium sdk but also from the base android sdk as well (here is the link for the solution on android: Changing Font Face on Android Webview). Using essentially the same approach for the titanium code, here is what I did:

1. Put the font file on the Resource directory of the Titanium project. In here, I am using Airstream.ttf for my custom font face and I placed it in a subfolder named 'fonts' on the Resource folder.

2. Set the css code to use the font face accordingly.
<style type="text/css">
  body {
    font-family:Airstream;
    font-size:20pt;
  }
  @font-face {
     font-family : "Airstream";
     src:url("Airstream.ttf");
  }
</style>

3. On your application code, copy the font file to the directory where your local html (to be rendered on the WebView) will be written. In my code, I just used the default application directory.

1:  var fontFile = Ti.Filesystem.getFile(Ti.Filesystem.resourcesDirectory + 'fonts/', 'Airstream.ttf');  
2:  var fontCopy = Ti.Filesystem.getFile(Ti.Filesystem.applicationDataDirectory, 'Airstream.ttf');  
3:  if (!fontCopy.exists()) {  
4:       fontFile.copy(Ti.Filesystem.applicationDataDirectory + 'Airstream.ttf');  
5:  }  

4. Write the html file in the same directory as the font file and load it on the webview:

1:  var htmlFile = Ti.Filesystem.getFile(Ti.Filesystem.applicationDataDirectory, 'test.html');  
2:  htmlFile.write(htmlContent);  
3:  if (htmlFile.exists()) {  
4:       webView.setUrl(htmlFile.nativePath);  
5:  }  

Here is what it looks like on the device: