Wednesday, December 15, 2010

Google SpreadSheet Library for Android

You might have already tried using Google's GData Lib to access SpreadSheet from Android, and after few hours of try, you start Google for any alternate solution. I have also spent number of hours without any solution.

So, I have developed SpreadSheet client Lib [ works on Android :-) ] and ideally work on any Java platform-
http://code.google.com/p/google-spreadsheet-lib-android/

Latest version: 2.1 (Added support for List Feed. Please visit above link to get more info.)

Supported Features:

1. Create/Delete Spreadsheet

2. List all stored Spreadsheets

3. Add/Delete WorkSheet into/from a given SpreadSheet

4. List all Worksheets of a given Spreadsheet

5. Add Records into WorkSheet/SpreadSheet (It supports Table based record handling)

6. Retrieve Record from WorkSheet/SpreadSheet (Structured Query support)

7. Retrieve Record as List Feed from Worksheet

8. Update/Delete Records

9. Share ShreadSheet with user/group/domain.

10. Conditional data retrieval- Structured Query support

11. Conditional/Structured query support for List based data retrieval

12. Better Log handling. By default logging will be enabled. To turn off logging Log.disableLog()  

Would appreciate your feedback and love to hear any specific feature requirement.... happy to help :-)

Monday, December 6, 2010

Phone Away Widget

This Android widget will allow users to set their status and auto-response of phone calls. So, next time you are having dinner or doing anything much more interesting than attaining a call :-), you can use this widget to auto reply with an SMS message without disappointing or keep your caller guessing for your unanswered call.

Supported Platform
Android 2.1 and above.

How to use ?

1. Download PhoneAwayWidget.apk and add the widget on your Home screen. By default it will set you status "Available", which means your phone will behave as it is.

2. When you don't want to attain call and set status message, click on the widget, which in turn will launch the preference screen.



3. So if you set your status, next time call comes, it will auto-response with SMS message. You can define the mximum number of SMS auto-response, e.g. Max SMS Count = 10 means, for first 10 calls it will send SMS and rest of the calls it will just disconnect.

Please update me with your comments and any enhancement you want in this. Hope you'll like it. With this signing off...:-)

Monday, November 29, 2010

NoSuchMethodError in Android AIDL

Finally a good start of Monday :-). Resolved a weird problem of Android Framework which was disturbing me through out the weekend. One of my team mate (Sandeep) did exceptional R&D and helped me to come to this conclusion.

[Problem]
NoSuchMethodError exception while I was trying to access ISnsRequester.aidl of SNSProvider.
In Android 2.2 (Froyo) some of the method definitions of ISnsRequester.aidl file has been changed. A new input argument targetSubID has been added to commentPost() and commentRetrieve() methods.
But in our Android source code repository by mistake Telephony framework was still using older version of ISnsRequester.aidl (i.e. of Android 2.1).
This was the main cause of this problem.

For all framework classes/packages Android build system (when you try to make a binary) makes entry into Android\frameworks\base\api\current.xml In fact current.xml acts as Look up for any method or class reference. Thus definition of  commentPost() and commentRetrieve() methods were conflicting between current.xml and latest AIDL in SNSProvider. When my code was trying to call commentPost() and commentRetrieve() methods, being the look up for Framework, current.xml is being searched for the method definition instead of latest AIDL in SNSProvider. This was causing force close with NoSuchMethodError exception.

[Conclusion]
If any AIDL is part of Android Frmaework be careful about any duplicated resource or method definition conflicts and verify the current.xml after build is over.


Huh it really made me Nuts...:-D

Thursday, November 4, 2010

Certificate Exception in Google Data API Authentication


You are running the Google Data API samples for the first time and got the following exception-
javax.net.ssl.SSLHandshakeException: sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target

It’s definitely SSL certificate error, but it took me a while to figure out the actual cause and the resolution. So thought to share the finding. As we all do :-), I did Google and got this site helpful- http://www.java-samples.com/showtutorial.php?tutorialid=210 it explains a generic solution to this problem.

To resolve this Google Data API connection error, you need to import Google Server certificate into your JDK Keystore. Data API does authentication using following URL- https://www.google.com/accounts/AuthSubRequest

To get the certificate, access https://www.google.com/accounts/AuthSubRequest from your browser (IE)
At the bottom right corner of IE, you can find the SSL icon-
 
Double click the SSL icon and copy the certificate into file (in DER encoded binary X.509 (.cer) format). Save the certificate say as c:\google_auth.cer

Now import this certificate into JDK Keystore ([JDK_INSTALL_PATH]\jre\lib\security\cacerts) using keytool command-
keytool -import -alias google -keystore "[JDK_INSTALL_PATH]\jre\lib\security\cacerts" -file c:\google_auth.cer
-Password: changeit

Sample output-

Note the MD5 from the above output.

You can now validate whether this certificate has been added to the JDK keystore. To do that, display the list of registered certificates using,
keytool -list -keystore "C:\Program Files\Java\jdk1.5.0_22\jre\lib\security\cacerts"
-Password: changeit
Check whether you can find the MD5 (noted in the above step) in the displayed list of registered certificates. If you find the match, this indicates, Google Authentication SSL certificate has been successfully added to JDK Keystore.

Now, try again that sample application. It should be able to do the authentication successfully. Hope this helps.

Monday, November 1, 2010

Android Remote Service


This tutorial is to demonstrate usage of AIDL Interface and interacting 2 Android applications through Service. You can get the complete example source code- RemoteService Example and RemoteService Calling Example 

As we all know Android Service concept is good for tasks running in the background. Based on scope of accessibility services are of 2 types- Local and Remote. As the name indicates, Local Service can be accessed only within the process or application which it is part of. On the other hand, Remote Services can be accessed from different process/application and thus it posses inter-application communication use cases e.g. you are running one service to provide Geo Location for Cell ID. So, any application can read the Cell-ID and access your service to get Geo Co-ordinates. 

As the usability increases so as the building blocks for creating Remote Service. The first challenge is to do inter-process communication so that one application running on one process can access services running on another process. To achieve this IPC (Inter Process Communication) Android has provided a concept of AIDL Interface which acts as the communication interface between 2 processes.  

Following section explains steps to create a Remote Service and an Application to call that service- 

Steps to create a Remote Service
1.     Create an AIDL Interface. Define methods which you are planning to expose to client applications. AIDL interface syntax is similar to Java. It supports most of the Java primitive data types and does not need explicit import statements. Though for custom classes you need to add specific import statements.
a)     Create the interface file, PrasRemote.aidl under pras.service.aidl package. I have defined one method sayHello(String name) which I’ll access from client application and pass some name and it will return “Hello [Name]
         package pras.service.aidl;
         interface PrasRemote {
String sayHello(String name);
}  
b)    If there is no syntax error, it will generate a Java file under gen folder pras.service.aidl.PrasRemote.java

2.     Define the implementation of the methods defined in Step 1.
package pras.service;

import android.os.RemoteException;
import pras.service.aidl.PrasRemote;

/**
 * Implementation of AIDL interface method
 *
 * @author prasanta
 */
public class MethodImpl extends PrasRemote.Stub {

      public String sayHello(String name) throws RemoteException {
            return "Hello "+ name;
      }
}

3.     Define the Service.
package pras.service;

import android.app.Service;
import android.content.Intent;
import android.os.IBinder;
import android.util.Log;

/**
 * The actual Service class which will receive remote calls from Clients
 *
 * @author prasanta
 */
public class PrasService extends Service {

      String TAG = "PrasService";
      @Override
      public IBinder onBind(Intent intent) {
            Log.i(TAG, "onBind_________________________");
            //Return Instance of MethodImpl.java which implements AIDL Interface
            return new MethodImpl();
      }
}

4.     Add entries into Manifest for the service defined in Step 3
[service android:name=".PrasService"]
[intent-filter]
            [action android:name="com.my.service.REMOTE_SERVICE"/]
      [/intent-filter]
[/service]
An intent action having value com.my.service.REMOTE_SERVICE need to be used to call this Service from Client Application

Steps to Call the Remote Service-
1.     Create a new Android project. 


2.     Copy the AIDL file i.e. PrasRemote.aidl file into this new Application Project. Please make sure you are keeping the .aidl file in the same package name as you define in RemoteService application i.e. pras.service.aidl Otherwise it might cause java.lang.SecurityException : Binder invocation to an incorrect interface  
3.     Create a Listener class which implements ServiceConnection Interface and handle call backs when connected to Remote Service. ServiceConnection interface has 2 methods- onServiceConnected(ComponentName cmp, IBinder binder) which will get invoked when client is connected to RemoteService and onServiceDisconnected(ComponentName cmp) if unexpectedly it gets disconnected.
onServiceConnected will provide a IBinder instance which will be casted to get instance of the Interface i.e. PrasRemote. Now you can call the method i.e. sayHello() using this instance.


PrasRemote remoteIntf = PrasRemote.Stub.asInterface(binder);
try{
   String remoteMsg = remoteIntf.sayHello("Prasanta");
}catch(RemoteException ex){}  


4.     Define an UI to Bind and Unbind RemoteService. Execute following when user click on “Bind_Remote_Service” button-
RemoteServiceCon serCon = new RemoteServiceCon(this);
Intent intent = new Intent("com.my.service.REMOTE_SERVICE");
bindService(intent, serCon, Context.BIND_AUTO_CREATE);

To unbind-
unbindService(serCon);

Kindly note: bindService() and unbindService() are methods of Context.java

  

Wednesday, September 8, 2010

Android Contacts DB Internal


Important Contact DB Tables:
This article describes few of the important tables of Contact Application Database- raw_contacts, contacts and data. Following section will describe usage of few of the important columns of these tables-


raw_contacts- stores entries for all contacts. So if you have 100 contacts, there will be 100 records in this table. For the purpose of data normalization and reduce data redundancy,  this table stores basic contacts details and foreign keys of other tables (e.g. contacts tables) which in turn stores particular contact details like count of links, whether contact has email id etc.
Column Name
Purpose
Id
unique ID for each Contact
display_name
Contact name (first and last name are clubbed together)
display_name_reverse
. This column is read when you set display order “reverse” instead of display_name
account_type
Source of the account- SIM, Phone, Google, T-Mobile etc. There can be one entry for the owner profile vnd.sec.contact.my_profile
contact_id
Foreign key for contacts table. This field is important when contacts are linked.

Contacts- this table is directly referred while creating Contact List. If a contact is linked with another, its entry will be deleted from this table and will not be displayed in the Contact List.
Column Name
Purpose
Id
unique ID for each Contact
display_name
Contact name (first and last name are clubbed together). Same as raw_contacts table
display_name_reverse
Same as raw_contacts_table
link_type1
Same as account_type of raw_contacts
link_count
How many contacts are linked to this contact
has_email
Probably it helps to quickly check whether a contact has email id rather than reading entry from data table.

Data- this table stores all possible contact details e.g. multiple phone numbers, emails, icons, birthday, company name etc.
Column Name
Purpose
mimetype
Type of data. 5- display name, 6-phone _number, 1- email, 7-contact icon etc.
raw_contact_id
Foreign key for contacts table. This field is important to find out primary entries of a particular contact
data1
Stores contact details row wise. So for 3 details e.g. , and , there will be 3 rows.
data2
. (Fix me: some other numerical code also present.)
data3
. (Fix me: some other numerical code also present.)
data15
Stores contacts icons in binary format (PNG)


Important Contact URI and Sample Usage

content://com.android.contacts/raw_contacts_with_photo

Authority: com.android.contacts (It identifies the ContactsProvider class. So in all URI it will be a constant part.)
Authority Information defined in ContactsProvider Manifest-
<provider android:name="ContactsProvider2"
android:authorities="contacts;com.android.contacts"
../>

Path: raw_contacts_with_photo

Following is a list of important URI to access 3 different tables of Contact Application i.e. contacts, raw_contacts and data- 
Accessing Contacts Table
content://com.android.contacts/contacts
content://com.android.contacts/contacts/#
content://com.android.contacts/contacts/#/data
Accessing Raw_Contacts Table
content://com.android.contacts/raw_contacts
content://com.android.contacts/raw_contacts/#
content://com.android.contacts/raw_contacts/#/data
Accessing Data Table
content://com.android.contacts/data
content://com.android.contacts/data/#
content://com.android.contacts/data/phones
content://com.android.contacts/data/phones/#