RSS Feed

SMS App – Improved

Posted on

Welcome back everyone, today we will continue the development of the SMS App adding two functionalities. We will be able to send SMS and integrate with the contacts list.

In the last post I comment about Tizen’s features, that is a way to restrict what your App can access in the system. Now we will need to add one feature to our App, the ability to read the contacts list. We could give access to the entire contact API, however we are only reading the contacts list so we will add the feature to be able to read the address book only. So go to the config.xml and add the new feature, after you add the feature your config.xml should look like this:

  • HTML – Changes

Let’s start with the HTML pages, because they are easier to explain and less code as well.

First in our main page we will add one link to the control bar, this link will take the user to the compose SMS screen.

Check the code:

<div id="home" data-role="page">
        <div data-role="header">
             <center><h1>Messages</h1></center>
        </div><!-- /header -->

        <div data-role="content">
             <ul id="messages" data-role="listview"
                 data-autodividers="alpha" data-shortcutscroll="true">
                  <li><span>    </span> </li>
             </ul>
       </div><!-- /content -->
       <div data-role="footer">
            <div data-role="controlbar" data-style="tabbar">
                    <ul>
                    <!-- NEW LINK  BELOW -->
                    <li><a href="javascript:composeSMS();"
                           data-icon="ctrlbar-compose">Compose SMS</a></li>
                    <li><a href="javascript:aboutApp();"
                           data-icon="ctrlbar-info">About</a></li>
                    <li><a href="javascript:exitApp();"
                           data-icon="ctrlbar-close">Exit</a></li>
                    </ul>
           </div><!-- /navbar -->
       </div><!-- /footer -->
</div><!-- /page -->

You may notice the new link at line 16.

Now let’s pass to the page that will show our SMS thread this page is used to compose a new SMS as well.

<div id="message_view" data-role="page">
        <div data-role="header">
             <span id="contact_name"></span>
        </div>
        <div id="content_sms" data-role="content">
            <input type="hidden" id="contact_number"/>
            <ul id="message_thread" data-role="listview"
                data-autodividers="alpha" data-shortcutscroll="true"
                data-inset="false" data-filter="true"
                data-split-icon="star" data-theme="a"
                data-dividertheme="a" data-split-theme="a">
            </ul>
            <div data-role="fieldcontain">
                <label for="sms_to_send">Message:</label>
                <input maxlength="160" type="text" id="sms_to_send"/>
            </div>
        </div>
        <div data-role="footer" data-position="fixed">
            <div data-role="controlbar" data-style="toolbar" >
                  <ul>
                       <li>
                          <a href="javascript:sendSMS();"
                             data-icon="ctrlbar-share">Send</a>
                      </li>
                      <li>
                          <a id="add_contacts" style="visibility: hidden"
                             data-icon="ctrlbar-contacts"
                             href="javascript:contactPopulate();">
                         Add Contact</a>
                     </li>
                  </ul>
            </div>
        </div>
</div>

Basically we added three things here first at line 22 a link to send the SMS, at line 26 a new link in the control bar to change the page to the contact list and at line 13 we added a div with the data-role “fieldcontain” that have a label and a input text so we can write a message.
The link to add contacts will only be visible when we are composing the SMS, otherwise we won’t see it

If we want to integrate with the contact list, we’ll need a page that will show all the contacts so we can select them.
The code is pretty easy, it is just a page with a header and a content and inside the content we will put a list that the contacts will reside in.

<div id="contact_search" data-role="page">
          <div data-role="header">
              <h1>Contacts</h1>
          </div>
         <div data-role="content">
              <ul id="contacts_list" data-role="listview"
                  data-autodividers="alpha">
                    <li><span>    </span> </li>
              </ul>
         </div>
</div>

One important thing to mention is the property “data-autodividers=alpha”, this is used by Tizen to automatically order the list alphabetically.

  • The Javascript

Now that we have our pages ready, it’s time to start the hard work !

You may notice that I made a lot of changes in the Javascript code and code insertions as well.

First when the program is opening we will execute this function to access the contacts list. You may notice that we are calling the Tizen contact API to get the default address book that we have in the phone.


//Just a call to the Tizen API
function loadContacts(){
       addressBook = tizen.contact.getDefaultAddressBook();
}

Now when we are loading the initial screen, the one that shows my SMSes, we will now show the name of the person if we have his/her phone  number in the contact list.

To be able to do this the function messageQueryCallBack must be modified. We will do just like the last time, iterating in all messages, but this time we will check from send the message so we can put the name of the contact in the screen (if we have her/him on the address book), otherwise we will just print the phone number.

You can check the code:

//Show who sent you messages (Main page)
function messageQueryCallback(messages){
    messagesGlobal = messages;
    messageGlobalByUser = {};
    var alreadyInserted = {};
    var element = "";
    var from, to, id,firstName,lastName,contact;
    var filter;
    var smsRepeat;
    id = "";
    firstName = "";
    smsRepeat = 0;

    //Iterating all messages
    for(var i = 0; i < messagesGlobal.length; i++){
        from = messagesGlobal[i].from;
        to = messagesGlobal[i].to[0];

        /* Because when we send a message, the from field is empty. And we
          don't wan't to show our messages in the main screen */
          if(from != "" && from != null  && !alreadyInserted[from]){
            alreadyInserted[from] = true;
            id = from;
         }
         else if(!alreadyInserted[to]){
            alreadyInserted[to] = true;
            id = to;
         }
         else{ //Don't draw!
           id = null;
         }
         //Searching for the contact in the address book
         if(id != null){
           element = '<li>'
                     +'<a id="a-name-'+parseInt(id)+'" href="javascript:seeMessageContent('+id+');">'+
                     '<span >'+
                     id+'</a></span></li>';
           $('#messages').append(element);

           filter = new tizen.AttributeFilter('phoneNumbers.number','CONTAINS', id);
           addressBook.find(
                       function(contacts){
                           if(contacts.length > 0){
                               contact = contacts[0];
                               firstName = contact.name.firstName;
                               lastName = contact.name.lastName;
                               if(lastName == null){
                                    lastName = "";
                               }
                               name = firstName + lastName;
                               $('#a-name-'+parseInt(contact.phoneNumbers[0].number)).text(name);
                               $('#a-name-'+parseInt(contact.phoneNumbers[0].number)).
                               attr('href',
                               'javascript:seeMessageContent(\''+contact.id+'\');');
                          }
                      }, onError,
                         filter);
        }
        //I received the message
        if(from != "" && from != null){
             if(!messageGlobalByUser[from]){
                   messageGlobalByUser[from] =
                     [[messagesGlobal[i], 0]];
            }
            else {
                messageGlobalByUser[from].
               push([messagesGlobal[i], 0]);
            }
        }
         else { //I sent the message

            if(smsRepeat % 2 == 0){
                   if(!messageGlobalByUser[to]){
                        messageGlobalByUser[to] =
                        [[messagesGlobal[i], 1]];
                   }
                   else {
                    messageGlobalByUser[to].
                    push([messagesGlobal[i], 1]);
                  }
            }
            smsRepeat++;
         }
    }

}

Now that we are able to send SMS this list may contains SMSes that I sent, this means that the field “from” is empty. So if I want to show to whom I sent the message we must check the field “to” to retrieve the phone number. After I know if i use “to” or “from” we will query the address book then retrieve the name of the person.To do this we use the Tizen’s attribute filter like we used before to query the SMS.  The phoneNumbers attribute is an array so this time in the query we must use ‘contains’. After we specified the filter we use the addressBook.find to look for the contact, this method has three parameters: the function success callback, the error function callback and the filter. If everything goes OK the success callback will be called receiving an array of contacts, this array will be empty if it didn’t match anything using the filter, then we just change the value of the link to display the name of the contact instead of the phone number.

Now we must add the messages to the messageGlobalByUser hash, it’s almost the same thing with a minor change. To be able to know who sent the message we will use a flag. the 0 will means that I receive the SMS, 1 I sent (Later you will discover why I’m doing this). I’m using the smsRepeat variable because Tizen keeps a copy of each message that I sent and if I didn’t use this logic I would print the same message twice!

We now have  a link to compose SMS, so let’s see this function:

function composeSMS(contactId){
    var contact,fistName,lastName;

    $.mobile.changePage('#message_view');
    $('#message_thread').html('');
    $('#add_contacts').css('visibility','visible');

    if(contactId != null){
        contact = getContact(contactId);
        lastName = contact.name.lastName;
        firstName = contact.name.firstName;
        if (lastName == null){
             lastName = "";
        }
        $('#contact_name').html('<h1>'+
$('<div/>').text( firstName + ' '+lastName ).html()+
'</h1>');
        $('#contact_number').val(contactId);
    }
    else{
        $('#contact_name').html('Select a contact');
    }
}

What we are doing here is: Change the page to the message view and set the button to add contacts visible!

If you pay attention you will notice that we receive the contactId as a parameter, in this case when we Click to compose the SMS we don’t know the contactId yet, so it will be null. So we must select a contact to send the SMS. To do this we use the function populateContactList that is called when we click in the link “add_contacts”.

Here is the code:


function populateContactList(){
     var filter;
     //Get the entire address book
     filter = new tizen.AttributeFilter('name.firstName','EXISTS', '');
     addressBook.find(contactsCB, onError, filter);
}

We will use the method find again, but this time with a different parameter in the filter. This time we will use exists, so we are saying. If name.firstName exists, bring everything to me!

Now passing to the callback is very easy, we will receive an array of contacts so we just iterate on it populating the list.

//Populate the list with the contacts
function contactsCB(contacts){
    var contact;
    var element;
    var firstName,lastName;
    //Reseting
    $('#contacts_list').html('');
    for(var i = 0; i < contacts.length; i++){
        contact = contacts[i];
        firstName = contact.name.firstName;
        lastName = contact.name.lastName;
        if(lastName == null){
           lastName = "";
        }
       element = '<li "ui-li-1line">'+
                 '<a href="javascript:composeSMS(\''+contact.id+'\');">'+
                 '<span>'+
                 $('<div/>').text( firstName +
                 ' '+lastName).html()+
                 '</a></span></li>';
       $('#contacts_list').append(element);
     }

}

Note: This time we have a link to composeSMS again and you can see that the contactId parameter is not going to be null, so the name of the contact will appear in the header.

Imagine now that you wrote your SMS and you clicked in the button send, the function sendSMS will be called to send the SMS.

Here it is:


function sendSMS(){
         tizen.messaging.getMessageServices("messaging.sms",
         sendSMSCallBack,onError);
}

The Tizen messaging api can handle a  lot of message types like SMS and email. So we must retrieve the SMS service to be able to send a SMS and we do this using the tizen.messaging.getMessageServices.

Now in the callback sendSMSCallBack we actually send the SMS

//Send the SMS to the recipients
function sendSMSCallBack(services){
     var msg,content;
     var contact;
     var phoneNumber;

     if(services.length > 0){
         content = $('#sms_to_send').val();
         contact = getContact($('#contact_number').val());

         //This means we don't have the contact in the list.
        //We only have the phone number
        if(contact != null){
            phoneNumber = contact.phoneNumbers[0].number;
        }
        else {
            phoneNumber = $('#contact_number').val();
        }
        if(phoneNumber == null || phoneNumber == ""){
            alert('Add a receipient');
            return;
        }
        msg = new tizen.Message("messaging.sms", {plainBody:content,to:[phoneNumber]});
        timeLastMsg = msg.timestamp.toLocaleDateString();
        services[0].sendMessage(msg, messageSent, onError);
    }
    else {
        alert('SMS not supported - No SMS service in the phone');
    }
}

In this callback we will receive an array of SMS services, but we only have one so we will use the first one. Then we get the message content from the text box and to who we are sending the message and look in the addressbook for the number. After this we create a new message  using new tizen.Message(), then we send it. It’s good to know that when we are creating a message in the “to:” value we can put as many phoneNumbers as we want. So if i want to send a message to N people it would be like this:

msg = new tizen.Message("messaging.sms", 
{plainBody:content,to:[phoneNumber, phoneNumber2,..., 
phoneNumberN]});

The messageSent Callback is just a function to put the message that we just write it in the screen, it’s so trivial that i won’t put it in here.
(timeLastMsg is used in the messageSent callback just to show the date that the message was sent)

Now moving to the last part, we will talk how we will show the messages to the user. We already did this in the last post, but now
we also need to show the messages that I sent. So here is the code:

//Print message content
function seeMessageContent(contactId){
    var contact = getContact(contactId);
    var message,bubbleSideId,bubbleSide,messages;
    var firstName, lastName;
    var phoneNumber;

    $.mobile.changePage('#message_view'); //Change page view
    $('#message_thread').html('');
    $('#add_contacts').css('visibility','hidden');

    if(contact != null) {
        firstName = contact.name.firstName;
        lastName = contact.name.lastName;
        if(lastName == null){
            lastName = "";
        }
        $('#contact_name').html('<h1>'+
                $('<div/>').text( firstName + ' '+lastName ).html()+
                '</h1>');
        $('#contact_number').val(contactId);
        phoneNumber = contact.phoneNumbers[0].number;
    }
    else {
        contactId = '+' + contactId;
        $('#contact_number').val(contactId);
        $('#contact_name').html('<h1>'+
                $('<div/>').text( contactId ).html()+
                '</h1>');
        phoneNumber = contactId;
    }
    for(var i = 0; i < messageGlobalByUser[phoneNumber].length; i++){
        messages = messageGlobalByUser[phoneNumber];
        message =  messages[i][0];
        bubbleSideId = messages[i][1];

        if(bubbleSideId == 0){ //received
            bubbleSide = "left";
        }
        else { //I sent
            bubbleSide = "right";
        }
        $('#message_thread').append('<li>'+
              $('<div/>').text( message.body.plainBody ).html()+
              '<span>'+
              message.timestamp.toLocaleDateString()
              +'</span></li>');
       }

}

Basically is the same thing as the last time, but now we need to  take because we will change the balloon according to who sent the message. And we also put the name of the user in the header if we have him/her in our address book. Limitations: That problem when you receive a SMS when you are in the program and you need to close it and open again to see it still there and and to send a SMS you must have the number in the contact list if you didn’t receive any message from the person.

  • Running the App

Install the app in the emulator and let’s add a contact. So open the App called “contacts” and add a contact:

Now let’s send a message to this new contact, open the Messages App and go to compose SMS than chose the contact, write somethig and send it!

You may notice the event injector by the right. Take a look at received messages, you will see the number of the contact and the message.

Now close the app the send a message with the same number, and open the App again.

(I sent the message “Hello Emulator”)

You should see this:

You can always check the good and old Tizen API here: https://developer.tizen.org/documentation

Also you can grab the source code here: http://git.profusion.mobi/cgit.cgi/iscaro/FirstApp/

Advertisements

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: