A simple PIM example

Now that I’ve got my SMS Checkers game up and running, I’d like to play it against a friend. But I don’t want to have to type my friend’s mobile number into that little phone number text field every time — really I don’t even know his number off the top of my head since I always just call people by selecting numbers from my address book. What to do?

This looks like a job for JSR 75: PIM!!!

JSR 75 also covers the File Connection API, but for today let’s talk about the Personal Information Management API.

Browsing through the JavaDoc, it seems pretty clear that this API is one where they’ve opted for flexibility over simplicity. The addressbooks, calendars, and to-do lists on the various handsets each have a fixed structure, however there’s no reason to expect all of these personal information datastores to have the same structure as each other. So the PIM API was designed to allow you to find the fields and records you need regardless of the underlying structrure of the datastore.

It’s actually a little confusing to try to figure out from the JavaDoc how to get the information you want. Fortunately, there aren’t too many classes. The classes to focus on are PIMItem and PIMList, which essentially describe records and record stores respectively. Between these two classes (and subclasses such as Contact), you’ll find the methods you need to determine what fields (such as TEL) a record has data for, which attributes (such as HOME or MOBILE) are associated with the field, and what type of data the (such as String or int) is contained in the field.

Confused yet?

My first instinct in such a case is to just write a simple example program.

It took a few tries, so I was a little disappointed that there was no clear() method to delete the whole ContactList so I could start over. Yet, it’s probably wise of the API designers to have left that off considering that in real life if your program deletes the user’s entire address book — even if he gave permission to modify it — this would lead to a “bad user experience” in every case. So it’s better not to even have the method there to tempt you to deliberately write some malicious code, which is a no-no in Java ;-).

The solution I found (for the WTK) is just to delete all the files in the following directory whenever I wanted to start over with a clean slate: WTK2.2/appdb/DefaultColorPhone/pim/contacts/Contacts/

The following class creates a couple of very simple records then iterates through the resulting record store printing out exactly what kind of data structure was created. Note that this example isn’t something you’d put in a real application (especially given all the System.out.println() statements). Also note that I made it a subclass of Thread. Accessing the PIM system is a potentially blocking operation that should not be done from any method that needs to return immediately such as startApp() or commandAction().

Here’s the code:

package net.frog_parrot.test;

import java.util.Enumeration;

import javax.microedition.pim.*;

/**
* A simple PIM testing utility.
*/
public class PIMRunner extends Thread {

  public void run() {
      try {
        ContactList addressbook
            = (ContactList)(PIM.getInstance().openPIMList(
            PIM.CONTACT_LIST, PIM.READ_WRITE));
        Contact contact = null;

        // Each PIMItem -- new or found -- is associated with
        // a particular PIMList.
        contact = addressbook.createContact();
        if(addressbook.isSupportedField(Contact.FORMATTED_NAME)) {
          contact.addString(Contact.FORMATTED_NAME, Contact.ATTR_NONE,
             "Lynn Hanson");
        }
        if(addressbook.isSupportedField(Contact.TEL)) {
          contact.addString(Contact.TEL, Contact.ATTR_HOME,
             "555-HOME-NUMBER");
          contact.addString(Contact.TEL, Contact.ATTR_MOBILE,
                            "555-MOBILE-NUMBER");
        }
        // Here's a quick search to see if this contact
        // is already present in the addressbook:
        Enumeration matching = addressbook.items(contact);
        if(matching.hasMoreElements()) {
          System.out.println("found the first contact");
        } else {
          System.out.println("adding the first contact");
          contact.commit();
        }
      
        // Let's create one more contact:
        contact = addressbook.createContact();
        if(addressbook.isSupportedField(Contact.FORMATTED_NAME)) {
          contact.addString(Contact.FORMATTED_NAME, Contact.ATTR_NONE,
             "Spencer Hobbs");
        }
        if(addressbook.isSupportedField(Contact.TEL)) {
          contact.addString(Contact.TEL, Contact.ATTR_HOME,
             "5555-HOME-NUMBER");
          contact.addString(Contact.TEL, Contact.ATTR_MOBILE,
             "5555-MOBILE-NUMBER");
        }
        matching = addressbook.items(contact);
        if(matching.hasMoreElements()) {
          System.out.println("found the second contact");
        } else {
          System.out.println("adding the second contact");
          contact.commit();
        }
            
        // Now print the contents of the addressbook:
        Enumeration items = addressbook.items();
        while(items.hasMoreElements()) {
          System.out.println("\n *** new item ***");
          contact = (Contact)(items.nextElement());
          int[] fields = contact.getFields();
          for(int i = 0; i < fields.length; i++) {
            int fieldIndex = fields[i];
            System.out.println(" field " + fieldIndex + ": "
                + addressbook.getFieldLabel(fieldIndex));
            int dataType = addressbook.getFieldDataType(fieldIndex);
            System.out.println(" * data type: " + dataType);
            if(dataType == PIMItem.STRING) {
              for(int j = 0; j < contact.countValues(fieldIndex); j++) {
                int attr = contact.getAttributes(fieldIndex, j);
                System.out.print(" " + j + ". (");
                System.out.print(addressbook.getAttributeLabel(attr) + "): ");
                System.out.println(contact.getString(fieldIndex, j));
              }
            }
          }
        }
      } catch(Exception e) {
        e.printStackTrace();
      }
  }
  
}

And here’s what it printed out:

adding the first contact
adding the second contact

*** new item ***
field 105: Formatted Name
* data type: 4
0. (None): Lynn Hanson
field 114: Revision
* data type: 2
field 115: Tel.
* data type: 4
0. (Home): 555-HOME-NUMBER
1. (Mobile): 555-MOBILE-NUMBER
field 117: UID
* data type: 4
0. (None): 1.vcf

*** new item ***
field 105: Formatted Name
* data type: 4
0. (None): Spencer Hobbs
field 114: Revision
* data type: 2
field 115: Tel.
* data type: 4
0. (Home): 5555-HOME-NUMBER
1. (Mobile): 5555-MOBILE-NUMBER
field 117: UID
* data type: 4
0. (None): 2.vcf

Advertisements

40 comments so far

  1. FabachM on

    Hi,

    How is it possible to test this sample Java Application??
    Thanks

  2. carolhamer on

    If you don’t have the Wireless Toolkit installed, then start by installing it (explained here).

    Then create a new project (from ktoolbar), and when the “project settings” GUI pops up, be sure to check the box for “PDA profile for J2ME (JSR 75)”.

    Copy the above code into a file called PIMRunner.java in the source code directory of the project. Then write a very simple MIDlet class for the project that does nothing more than create an instance of PIMRunner and start it running.

    Here’s the MIDlet class I used:

    package net.frog_parrot.test;

    import javax.microedition.lcdui.Command;
    import javax.microedition.lcdui.CommandListener;
    import javax.microedition.lcdui.Display;
    import javax.microedition.lcdui.Displayable;
    import javax.microedition.lcdui.Form;
    import javax.microedition.midlet.MIDlet;

    /**
    * A simple MIDlet to launch the PIMRunner.
    */
    public class PIMTest extends MIDlet implements CommandListener {

    private Command myExitCommand = new Command(“Exit”, Command.EXIT, 1);
    private Command myOkCommand = new Command(“OK”, Command.OK, 1);
    private Form myResultScreen;

    /**
    * Empty constructor.
    */
    public PIMTest() {
    }

    /**
    * Initialize the Displayables.
    */
    public void startApp() {
    myResultScreen = new Form(“Results”);
    myResultScreen.addCommand(myExitCommand);
    myResultScreen.addCommand(myOkCommand);
    myResultScreen.setCommandListener(this);
    Display.getDisplay(this).setCurrent(myResultScreen);
    }

    public void pauseApp() {
    }

    public void destroyApp(boolean unconditional) {
    }

    /**
    * Change the display in response to a command action.
    */
    public void commandAction(Command command, Displayable screen) {
    if(command == myExitCommand) {
    destroyApp(true);
    notifyDestroyed();
    } else {
    PIMRunner pr = new PIMRunner();
    pr.start();
    }
    }

    }

  3. fabachm on

    thank you for your answer.
    i will try it later. and after building the project, how can i execute the programm on my mobile?

  4. carolhamer on

    In ktoolbar, if you select project > package > create package, then ktoolbar will build a jar and jad file and place them in the bin directory of the project (eg. WTK2.0/apps/PIMTest/bin/PIMTest.jad & PIMTest.jar).

    From there, there are several ways to load the MIDlet onto the handset such as uploading the jar and jad to a website and downloading them from there or connecting your handset to your PC with a cable, etc.

  5. fabachm on

    okay thanks alot

  6. Kamal on

    I tried to install the application. but I am getting the following error.

    “This midlet suite contains reserved classes. installation will be cancelled”

    device: palm treo 680
    vm: weme 5.7.1

  7. carolhamer on

    That’s a very strange error message. It seems to be implying that the MIDlet suite is trying to override a class that is already defined by the platform (like java.lang.String for example). The MIDlet clearly isn’t doing that, but you might try renaming the two classes just in case (then be sure to update the jad/MANIFEST properties).

    Otherwise, it’s possible that it’s just a misleading error message. My device has given me strange messages (for example it gave a security error for a failed installation when the problem was that the jar was too big). It may be a mismatch of profile or configuration. If your device is a CDC device and not a CLDC/MIDP device, then the application probably won’t install.

  8. Kamal on

    Carolhamer,

    Thanks for your quick response.

    I am including jsr75.jar file along with my application. Is this OK?

    And also, Do i need to sign my midlet in order to get the optional packages working in device?

  9. Kamal on

    Also when i dont include the jsr75.jar in application, i m getting ClassNotFoundException.

  10. Avi on

    hi im trying to use your example as a guideline test for a projectt. I just started learning about the jsr 75 and i find it quite complex. Im trying to run ur example using netbeans and it comes with hundreds of errors. any idea of what should i do ?

  11. carolhamer on

    Hundreds of errors? I would recommend starting with a simpler example. I would start by making sure that you can get a basic MIDlet to compile (without using JSR 75). Then try merely importing the JSR 75 classes to see if you can do that in your current build environment. Once you’re sure you have access to the JSR 75 APIs, the rest should compile.

  12. Rahjesh on

    Hi,
    The problem here is the target device is not having
    JSR75 installed. To install JSR75 in Treo palm follow these steps.
    1. Download IBM WEME 5.7.2
    2. Extract the contents and you will see a folder JSR75 inside.
    3. Copy the files fileconnect.prc, pimop.prc, PIMPrefs.prc to the device an soft restart the device.
    4. Now you can use PIM APIs.

  13. Nanda on

    Guys, the reason for bulk errors could be the format of the double quotes. change it in both the classes( the midlet and the thread) and replace once again with the double quote of your key board, it works very fine.

    cheers.

  14. Nanda on

    Guys, the reason for bulk errors could be the format of the double quotes. change it in both the classes( the midlet and the thread) and replace once again with the double quote of your key board, it works very fine.

    And I appreciate the good efforts by carolhamer.

    cheers.

  15. carolhamer on

    Thanks Nanda! Good point!

  16. sujit on

    hi.
    i want to learn j2me i hav installed
    wireless toolkit 2.5

    now i am blank….how 2 start doing projects

    hope 2 get a quick response

  17. Vineet Billorey on

    Hi. You have demostrated the PIM example, but can u show me how to add these records to a text file and how to transfer this file to the webserver.

  18. carolhamer on

    Hi Sujit,

    Sorry I’ve been neglecting the comments on this blog since I’ve been busy moving to Switzerland. To get started on learning J2ME, you could always try my book. I focus on game programming, but cover a range of J2ME topics from the beginning.

    Hi Vineet,

    Regarding putting the contacts and other data on a web server in order to import them directly into the handset’s contact list: I don’t have an example MIDlet handy that does this, but it should be fairly straight-forward.

    The JavaDoc for the class javax.microedition.pim.PIM gives an example of how to import contacts from a stream. So what you need to do on the client side is open an instance of HttpConnection and get the InputStream from it to pass to the importVCard method (from the PIM JavaDoc). My “Dungeon” example (from my book) illustrates both the client side and the server side of a simple Http data transfer. The same Http data transfer code can be used to transfer VCard data to be read by the PIM API.

  19. jin on

    helo

    is this blog still up? just need to ask some questions about PIM

    thanks for replying

  20. carolhamer on

    Yes, this blog is still alive. 😉

  21. stefano on

    what picture from VCards ?
    is it possible to display them on screen through java?

    i read that the image format of VCard is something like :

    PICTURE: BASE64: AGTRHYSAETG#$T^$W (<- data of image)

    assuming that base64 is universal for the encoding among all phones ,
    it should be a straight forward method ,
    of simple taking the data ( String ? or Bytes ? )
    doing Base64 decode
    create Image[] from bytes
    and display

    has anyone ,
    thought / know / tried
    anything like this ?

  22. Michiel on

    Hi,

    Thanks for this example, it did help me getting a rough picture of how to work with the PIM classes.

    However, I do have a question: how can I access/create a contacts database of my own? According to the javadoc openPIMList is also available with a third parameter:

    openPIMList(int pimListType, int mode, String name): Opens the specified PIM list.

    Specifying a name I got the error:
    “my_contacts is not a valid PIMList” (“my_contacts” is my contacts database, ie. I don’t want to access the default blackberry contacts database).

    Does anybody have a hint on here this is going wrong?

    Thanks in advance!

  23. Michiel on

    Hi,

    After some more testing I found out that I only have the default “Contact List” available on my virutal device.

    So I probably have to add a new contacts database myself. Does anybody know how to do this with the virtual blackberry simulator (research in motion)?

    Thanks in advance & cheers!

  24. Jay on

    Hello Carol,

    I have been playing with JSR-75, especially the PIM API. My objective was to move contacts from one phone to another, however the individual manufacturer’s implementation of the vCard representation seems to be quite different, espcially when dealing with additional office no, secondary email address etc.

    Is there a standard way of representing the contact info so that it can be easily moved between devices without caring much for the actual implementation.

    Cheers
    Jay

  25. Jalil on

    Hi how i can install pim in my mobile phone? My phone is nokia 6600 . When i want install that comminq error ( corrupted file or invalid version )

  26. Bakary on

    Nice tutorial.

  27. D Chohan on

    Hi

    Does anybody know how to read the contacts from a mobile? The tutorial works if creating new contacts and reading them back.

  28. thirdy on

    Hi, I’m developing an application that will create a custom Number for every Number of a Contact. Then after that synchronize it to an online address book through KSoap.

    And I’m stuck at these questions.

    1.Is it possible to define application specific Field?
    2.Is it possible to define application specific Attribute?
    3.Is it possible to add a new application specific value in Contact.TEL and Contact.NAME?

    If none of them are possible then I would have to create a new Contact item in the Contact list w/c I think would be bad because that will double the number of contacts in the native client address book! Any help with my problem?

    Thank you very much!

  29. carolhamer on

    All — I don’t think that PIM is implemented in a completely standard way from one handset to the next. As Jay notes above, I think there is quite a bit of variation in individual implementations. Unfortunately, I haven’t researched this enough to have a list of specific data on the implementation differences from one manufacturer to another.

    Jalil — PIM is an optional API that is implemented by the handset manufacturer. If it isn’t already supported on your handset, then there’s nothing you can do to add it.

  30. igorkruk on

    Hello,

    I am developing my own MIDlet. I get access to contacts – I read contacts and than put them into List object.
    My problem is that after I read contacts they are unsorted (alphabetical). I don’t know why some contacts started with ‘A’ are the end of the list.

    1. Is it possible to read contacts sorted by NAMEs automatically?
    2. Is it possible to get list of contacts as default in telephone.
    3. Do you know any ways of sorting read contact list?

    thanks for any help.
    Regards,

  31. carolhamer on

    igorkruk — That’s interesting. What kind of device is it?

    The thing to keep in mind is that any behavior that isn’t specified in the JavaDoc is something that can (and will) vary from one handset to the next. In this case, the items() method indicates “the order is undefined” — and the other methods to get an enumeration of the contact list don’t appear to indicate any ordering option either. It’s better to implement the ordering yourself to ensure that it will work the same way on all devices.

  32. Bilal Asif on

    hello,

    How to sync contacts using PIM’s API?

    I am trying to develop a j2me app which synchronize my cell phone’s contacts with a web server. I am using PIM’s API for this but i just found that the contact detail which PIM is giving don’t contain attributes like Contact’s REVISION.

    so how can i sync my contacts using PIM’s API?

    has anyone tried
    this before ?

    Thanks in advance.

  33. carolhamer on

    Hi Bilal,

    According to the JavaDoc, REVISION is one of the explicitly defined fields that may be present in a Contact — and it does give the date the contact was last revised.

    However, devices vary in terms of which which fields they support. You should probably have your program start by calling isSupportedField(REVISION) on your ContactList, to check if the program is running on a platform that supports the field. If so, you’re good to go, and if not, then you’ll probably have to find some other strategy for synchronizing.

  34. guruworld on

    Hi….Have been trying to edit the above code.The PIMRunner class and the MIDlet code but still cannot get a way of displaying only the name and phone number in the form..

    Is there a way the displayed attributes ca be changed to show only the FORMATTED_NAME AND ATTR_MOBILE within the for loop.

    Thanks

  35. Farhan on

    How to Sync Contacts in Blackberry JDE. Please provide me code

  36. vishal on

    When i rum this program, the “adding first contact” is display, but after that i get this error
    adding the first contact
    javax.microedition.pim.PIMException: Error writing to contact DB, error=0x80000043retryCount = 0
    at com.nokia.mid.impl.isa.pim.PBSearchManager.commitItem(PBSearchManager.java:529)
    at com.nokia.mid.impl.isa.pim.PIMItemImp.commit(PIMItemImp.java:635)
    at com.nokia.mid.impl.isa.pim.ContactImp.commit(ContactImp.java:871)
    at PIMTest.run(PIMTest.java:50)

  37. Dennis on

    hi carolhammer i like the blog and require your help i want to backup my contacts to a webserver currently all i can do is view them any ideas

  38. Vidya Sagar.S on

    REALLY Such a Rescue!
    Javadoc for PIM are Simply Horrible!

    Very Thankful!
    🙂

  39. Neveen Adel on

    Hello,

    How can update an existing contact field when am using addString() function it create another field not update the existing field .

    Thanks in Advance

  40. Mohit on

    Hi, Thanks a lot for this post. It made my life easy as i am a newbie in this field.I will definitely follow your post 🙂


Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: