Expanding your test contacts
Being able to create a contact is nice, but you really need for them to have more information
than just a name in order to be useful. So, for the next step, add some telephone numbers to
the contacts. If you are familiar with the Address Book application already, and you should be,
then you know that a contact can have multiple phone numbers—each with a diff erent role
or locations. Aft er having seen how the NAME field is handled, you may well assume that the
telephone field, named TEL, would operate in the same manner; as a StringArray type.
You would be wrong though.
When it comes to the TEL field each field is a simple String and is given an additional
att ribute defining which kind of phone number it is. Let’s take a look at this with
the following code.
Time for action – adding telephone numbers
- Add the following code to the run method of the AddTestContacts menu item.
//TODO: Add Phone numbers
newContact1.addString(BlackBerryContact.TEL,
BlackBerryContact.ATTR_MOBILE, “555-555-1212″);
newContact2.addString(Contact.TEL,Contact.ATTR_HOME,
“555-555-1234″);
newContact2.addString(Contact.TEL,Contact.ATTR_FAX,
“555-555-9999″);
newContact2.addString(Contact.TEL,
Contact.ATTR_MOBILE,”555-555-1313″);
// This is bad!
newContact2.addString(Contact.TEL,Contact.ATTR_FAX,
“555-555-1414″);
What just happened?
Working with phone numbers may look very straightf orward, but there are many pitf alls to
look out for here as well. Each phone number is added using the addString method , which
should look similar to the addStringArray method that you just worked with. Again, the
proper method to add the field is the one that matches the fields’ type and has nothing to do
with the name of the field or its function.
Also, like the previous example, the first parameter to the method is the constant value
defining which field is being added, which in this case is TEL. Following the field indicator
though is the important part, called the field att ribute. The att ributes are used as a way
of providing additional information about a field. In this case, that information defines what
kind of phone number is being added.
Every add method requires an attribute field , but this doesn’t always make sense for
some fields. When this is the case, the att ribute ATTR_NONE should be used. The phone
number field though requires an att ribute. Att empting to use ATTR_NONE will in fact be
treated the same as ATTR_HOME.
newContact1.addString(BlackBerryContact.TEL,
BlackBerryContact.ATTR_MOBILE, “555-555-1212″);
Now that you’ve covered the basics, this line to add a mobile telephone number to John Doe
should be self explanatory.
newContact2.addString(Contact.TEL,Contact.ATTR_HOME,”555-555-1234″);
newContact2.addString(Contact.TEL,Contact.ATTR_FAX,”555-555-9999″);
newContact2.addString(Contact.TEL,Contact.ATTR_MOBILE,”555-555-1313″);
Now, as John Smith is a doctor, he will have many more ways to be reached, but you can
see that this also presents no problems for the Contact class . Again, this example uses the
Contact class to reference the constant values instead of the BlackBerryContact class.
This is fine, but there are some phone att ributes which are not available from the Contact
class. The Java standard Contact only provides for six telephone types, but the BlackBerry
Address Book application will allow eight. So what is the diff erence? The Home2 and Work2
numbers are specific to BlackBerry. The constants for these att ributes can be found only in
the BlackBerryContact class.
As long as you use one, and only one, of each att ribute, you will be in good shape, but things
get really messy when you try to add a number with the same att ribute again.
// This is bad!
newContact2.addString(Contact.TEL,Contact.ATTR_FAX,”555-555-1414″);
You may expect that adding a number with the same att ribute would simply replace any
existing value, but this is not the case. Instead, the system will add the number into the “next
available slot”. The results can be quite confusing because in this case, the number will be
placed into the PAGER att ribute because FAX is already populated. If the PAGER already had
a value, then it would be added to some other field that didn’t have a value.

Adding another phone number with the same att ribute as an existing number yields
unpredictable results.
The corollary to this is that if you are editing a contact in your application you can’t
just blindly add the TEL fields. You must first either remove the old field by using the
removeValue method, or change the value by using the setString method.
Either way, things are going to be a lot more complicated. You would think that there would
be methods for getting, setting, or removing values that match those for adding values, but
this is not the case either. There are getString , setString , and removeValue methods ,
but all of the methods rely on an index value and not the att ribute that was originally
supplied. This just reinforces the idea that att ributes are simply meant to provide additional
information about the field and nothing more.
So, if you wanted to change one of the TEL fields you first need to find the field with the
proper att ribute out of the list of TEL fields. Remember that this field is not an array though,
so even though there may be up to eight values, there may be as few as 0 and the order in
which they are stored apparently has nothing to do with their att ribute. The following code
fragment should serve as an example of how to update the ATTR_HOME phone number.
// The proper way to change a value
int count = newContact2.countValues(Contact.TEL);
for (int i= 0; i< count; i++)
{
if ((newContact2.getAttributes(Contact.TEL, i) & Contact.ATTR_HOME)
== Contact.ATTR_HOME)
{
newContact2.setString(Contact.TEL, i, Contact.ATTR_HOME,
"555-555-4321");
}
}
To start off , you can get the number of values in the field by calling the countValues
method . Once you know how many are there, a simple for loop is used to test each one.
In order to see if a value has the ATTR_HOME att ribute, you first get all of the att ributes of
the value by calling the getAttributes method . Some att ributes can be combined using
a bitwise OR, so to check for a specific att ribute you must test with the bitwise AND, which
eff ectively removes just the desired att ribute from any other combined att ributes. Once you
know that a value has the ATTR_HOME att ribute, you can call setString by using the index
value from the loop to change the value.
Like isaid, it’s a lot more complicated and as a result, ithink it is safe to suggest that you
not do it unless you really need to. There will always be special cases where such a thing is
desired, but in general, a user should be in charge of their contacts and not your application.
Besides, there is no way to stop a user from changing or deleting a contact that has been
programmatically added.
Expanding even more
After tackling the relatively complicated fields of NAME and TEL, the EMAIL field should be
a lot easier. Making sure that your contacts have an e-mail address is the whole point of
this task because these will be used later on when testing another feature. Knowing that
the Address Book application allows you to have up to three e-mail addresses, how would
you think they are implemented in the PIM? Is it implemented as a String with multiple
values (such as the TEL field), or as a StringArray (such as the NAME field)? If you chose a
String with multiple values, you chose correctly!
The EMAIL field actually fits well with this concept of a String field with multiple values.
Unlike the TEL fields, there are no att ributes that are att ached to each of the e-mail
addresses, so adding one simply adds it to the list and there is nothing more to be concerned
about. So let’s look at some code already!
Time for action – adding e-mail addresses
- Add the following code to the run method of _
AddTestAddressesAction under the proper comment line.
//TODO: Add Email Addresses
newContact1.addString(Contact.EMAIL,Contact.ATTR_NONE,
“John@Test.com”);
newContact2.addString(Contact.EMAIL,Contact.ATTR_NONE,
“JDoe@test.com”);
newContact2.addString(Contact.EMAIL,Contact.ATTR_NONE,
“JohnDoe@test.com”);
newContact2.addString(Contact.EMAIL,Contact.ATTR_NONE,
“Admin@test.com”);
What just happened?
Wow, that code segment looks really easy. The lines are all practically the same! Each line
specifies the field as EMAIL and the att ributes as ATTR_NONE, so there isn’t much more to
talk about except for the “what-ifs”.
Much like the TEL, things get a litt le trickier if you want to edit the contact in your
application, but not as tricky as they are with the PHONE field. The addresses are stored in
the same order that you added them to the field so you can use this fact to your advantage
when editing. Because there are no att ributes for the various e-mail addresses, it is best to
remember the index of each value when you read them out. In this way, when you need to
change the value you can use the setString method and provide the index of field.
Alternatively, you can remove one of the EMAIL values and add a new one, but this will also
change the order of the values in the field. Values that are added are always placed at the
end of the list.
The biggest thing to watch out for here is that you don’t add a fourth EMAIL value to the
field. This will cause an exception to be thrown that the application will have to handle. In
the case of this application, it just quietly fails and neither of the contacts are added.
You can also put bad data into the Address Book application by adding values with bad data.
For instance, the Email Address field in the Address Book application has special validation
logic to ensure that the value is actually a valid e-mail. If you leave out the @, for instance,
the user would see an error and not be allowed to commit the data. All of those safeguards
don’t exist when working directly with the PIM. This goes for phone numbers as well as for
any other formatt ed values. It is one more reason that you must be very careful about when
working with the PIM directly.
Finishing the test contacts
We have done enough work to solve the initial problem of getting some contacts with e-mail
addresses into the Address Book. However, there is one more area of the contact left to
tackle—the address itself. The ADDR field is a combination of the NAME and PHONE fields
in that each address is a StringArray, but there are multiple addresses which each have
an att ribute specifying what kind of address it is. Sounds confusing? It is by far the most
complex piece of PIM data. Seeing code always helps me, so let’s dive into the code and
tackle it head on.
Time for action – adding e-mail addresses
- Add the final code segment under the appropriate comment in the run method
of _AddTestAddressesAction.
//TODO: Add Addresses
String[] Address1 = new String[contacts.stringArraySize(BlackBerry
Contact.ADDR)];
String[] Address2 = new String[contacts.stringArraySize(BlackBerry
Contact.ADDR)];
Address1[BlackBerryContact.ADDR_STREET] = “123 Main St.”;
Address1[BlackBerryContact.ADDR_EXTRA] = “Apt. 4″;
Address1[BlackBerryContact.ADDR_LOCALITY] = “AnyTown”;
Address1[BlackBerryContact.ADDR_REGION] = “AnyState”;
Address1[BlackBerryContact.ADDR_COUNTRY] = “USA”;
Address1[BlackBerryContact.ADDR_POSTALCODE] = “12345″;
newContact1.addStringArray(BlackBerryContact.ADDR,
BlackBerryContact.ATTR_HOME,Address1);
Address1[BlackBerryContact.ADDR_STREET] = “345 Main St.”;
Address1[BlackBerryContact.ADDR_LOCALITY] = “AnyTown”;
Address1[BlackBerryContact.ADDR_REGION] = “AnyState”;
Address1[BlackBerryContact.ADDR_COUNTRY] = “USA”;
Address1[BlackBerryContact.ADDR_POSTALCODE] = “12345″;
Address2[BlackBerryContact.ADDR_STREET] = “20 N Oak St.”;
Address2[BlackBerryContact.ADDR_LOCALITY] = “AnyTown”;
Address2[BlackBerryContact.ADDR_REGION] = “AnyState”;
Address2[BlackBerryContact.ADDR_COUNTRY] = “USA”;
Address2[BlackBerryContact.ADDR_EXTRA] = “Suite 200″;
Address1[BlackBerryContact.ADDR_POSTALCODE] = “12345″;
newContact2.addStringArray(BlackBerryContact.ADDR,
BlackBerryContact.ATTR_HOME,Address1);
newContact2.addStringArray(BlackBerryContact.ADDR,
BlackBerryContact.ATTR_WORK,Address2);
What just happened?
This code should be prett y similar to the code that you saw for the NAME field. The first step
is to simply create an array of String object s of the proper size and once again relying on
the stringArraySize method to give that proper value. The only real diff erence here is
that the field specified in the code is the ADDR field.
String[] Address1 = new String[contacts.stringArraySize(BlackBerryCon
tact.ADDR)];
Once you have an array of the right size, setting the data for each part of the address is just a
matt er of referencing the right index within the array by using the constants already defined.
The names of the constant values for the ADDR field are so generic that they are confusing.
Address1[BlackBerryContact.ADDR_STREET] = “123 Main St.”;
Address1[BlackBerryContact.ADDR_EXTRA] = “Apt. 4″;
Address1[BlackBerryContact.ADDR_LOCALITY] = “AnyTown”;
Address1[BlackBerryContact.ADDR_REGION] = “AnyState”;
Address1[BlackBerryContact.ADDR_COUNTRY] = “USA”;
Address1[BlackBerryContact.ADDR_POSTALCODE] = “12345″;
Maybe, other parts of the world think in terms of “locality” and “region”, but isomehow
doubt it. As if those weren’t bad enough, the name ADDR_EXTRA just gives no help at all
towards understanding its use. This is just one of those things that you have to remember
when working with addresses in a contact though.
Once the address is fully populated, adding it to the field is the same as adding a TEL field
in that you also have to specify one of the two supported att ributes, either ATTR_HOME
or ATTR_WORK.
newContact1.addStringArray(BlackBerryContact.ADDR,
BlackBerryContact.ATTR_HOME,Address1);
The whole point to this is that an address can have more than one address in the contact
record and the second contact in the example code has been set up in this way. Because the
values for the ADDR field are based on their att ribute, the order in which they are added is
not important. However, the index is still important when it comes to updating or deleting
a value.
The ADDR field also follows the same quirks that the TEL field does. If you add a second
address with the ATTR_HOME att ribute, the att ribute will get silently reassigned to
ATTR_WORK if one doesn’t already exist. If there are already two addresses in the
contact, then an exception will be thrown so it is important to utilize the methods
for checking the field before adding new values.
Adding new address values isn’t that bad, but changing one is the worst of both worlds.
If you recall from working with the NAME field, you cannot change just one element
of the StringArray. You have to replace the entire StringArray by calling the
setStringArray method.
This quirk is somewhat annoying, but now adds the fact that there is more than one value in
the list and it can get prett y complex. In order to get the address you want, you have to find
it in the same way that you did for the TEL field. The home address will not be in the same
index position all the time so you must look at each address in the list (there are only two at
most) and test the att ribute to see if it has the att ribute you want.
Pop quiz
- What class do you use to get a list of PIM items?
- PimItem
- PimList
- PIM
- When adding a value to a PIMItem, how do you choose the proper method to use?
- Use the method whose name matches the value name, that is,
setFirstName() - Use the method whose name matches the data type of the value, that
is, setString() - Use the setValue()method
- For values that are an array, how do you change the value of one element in the array?
- Use the setStringArrayElement() method.
- Use the setArrayValue() method.
- You can’t set a single element in an array. You must replace the entire array
with a new array of values.






October 1, 2010
BlackBerry