Search icon CANCEL
Subscription
0
Cart icon
Your Cart (0 item)
Close icon
You have no products in your basket yet
Save more on your purchases! discount-offer-chevron-icon
Savings automatically calculated. No voucher code required.
Arrow left icon
Explore Products
Best Sellers
New Releases
Books
Videos
Audiobooks
Learning Hub
Newsletter Hub
Free Learning
Arrow right icon
timer SALE ENDS IN
0 Days
:
00 Hours
:
00 Minutes
:
00 Seconds

How-To Tutorials - Mobile

213 Articles
article-image-windows-phone-7-silverlight-location-services
Packt
02 Sep 2011
11 min read
Save for later

Windows Phone 7 Silverlight: Location Services

Packt
02 Sep 2011
11 min read
  (For more resources on this subject, see here.)   Introduction One of the most powerful features of smartphones today is location awareness. Windows Phone 7 is no exception. The wide consumerization of GPS around 10 years ago brought handheld GPS receivers for consumers on the go, but few individuals could justify the expense or pocket space. Now that smartphones have GPS built in, developers have built incredibly powerful applications that are location-aware. For example, apps that help users track their jogging route, get real-time navigation assistance while driving, and map/analyze their golf game. In this article, we will take a deep dive into the location API for Windows Phone 7 by building an application to help navigate during travel and another to map the user's location. Tracking latitude and longitude In this recipe, we will implement the most fundamental use of location services, tracking latitude and longitude. Our sample application will be a navigation helper which displays all the available location information. We will also review the different ways in which the phone gets its location information and their attributes. Getting ready We will be working in Visual Studio for this tutorial, so start by opening Studio and creating a new Windows Phone 7 application using the Windows Phone Application project template. All the location/GPS-related methods and classes are found in the System.Deviceassembly, so add this reference next: We will need some UI to start tracking and displaying the data, so go to the MainPage.xaml file, if it's not already open. Change the ContentPanel from a Grid to a StackPanel, then add a button to the designer, and set its Content property to Start Tracking. Next add four TextBlocks. Two of these will be Latitude and Longitude labels. We will use the others to display the latitude/longitude coordinates, so set their x:Name properties to txtLatitudeand txtLongitude respectively. You can also set the application and page titles if you like. The resulting page should look similar to the following screenshot: How to do it... The core class used for tracking location is the GeoCoordinateWatcher. We subscribe to the events on the watcher to be noticed when changes occur: Double-click on your button in the designer to go to the click event handler for the button in the code behind file. This is where we will start watching for location changes. Create a GeoCoordinateWatcher field variable named _watcher. Set this field variable inside your click event handler to a new GeoCoordinateWatcher. Next add a handler to the PositionChanged event named _watcher_PositionChanged. Then start watching for position changes by calling the Start method. Next add a handler to the PositionChanged event named _watcher_PositionChanged. Then start watching for position changes by calling the Start method. In order to use the position information, create the void handler method with parameters named sender of type object and e of type GeoPositionChangedEventArgs<GeoCoordinate>. Inside this method set the Text properties on the txtLatitude and txtLongitude text boxes to the coordinate values e.Position.Location.Latitude and e.Position.Location.Longitude respectively. Latitude and longitude as strings:Latitude and longitude are of type double and can be converted to strings using the ToString method for display. You should end up with a class that is similar to the following block of code: public partial class MainPage : PhoneApplicationPage{ private IGeoPositionWatcher<GeoCoordinate> _watcher; public MainPage() { InitializeComponent(); } private void butTrack_Click(object sender, RoutedEventArgs e) { _watcher = new GeoCoordinateWatcher(); _watcher.PositionChanged += _watcher_PositionChanged; _watcher.Start(); } void _watcher_PositionChanged(object sender, GeoPositionChangedEventArgs<GeoCoordinate> e) { txtLatitude.Text = e.Position.Location.Latitude.ToString(); txtLongitude.Text = e.Position.Location.Longitude.ToString(); }} That's it. You can now deploy this app to your phone, start tracking, and see the latitude and longitude changes on your screen. How it works... The watcher starts a new background thread to watch for position changes. Each change is passed to your event handler(s) for processing. Window Phone 7 provides location services through the following three sources: GPS: Satellite based Wi-Fi: Known wireless network positions Cellular: Cellular tower triangulation Each of these position providers has their strengths and weaknesses, but the combination of the three covers nearly any possible use case: GPS is the most accurate, but you must have an unobstructed view of the sky Wi-Fi can be accurate depending on how close you are to the access point, but you must be in the range of a known wireless network Cellular is the least accurate and only needs cell signal So if you're in an urban area with tall buildings, GPS may be intermittent but Wi-Fi networks and cellular coverage should be plentiful. If you are in a rural area, GPS should work well and cellular triangulation might help where available. Tracking altitude, speed, and course In this section, we will discuss the different types of location information that are provided by the GeoCoordinateWatcher and how they might be used. A quick look at the Object Browser shows us that the GeoCoordinate object has several interesting properties: In addition to Latitude and Longitude, there is Altitude, Speed, and Course, among others. Altitude and Speed are pretty self-explanatory, but Course might not be as obvious. Course is your heading or the direction you are going, given two points. The following table shows each property and its unit of measurement: Horizontal and Vertical Accuracy specifies the accuracy of Latitude/Longitude and Altitude, respectively, in meters. For example, this means your actual Latitude position is between the reported Latitude minus the accuracy value and the reported Latitude plus the accuracy value. The smaller the accuracy value, the more accurate but the longer it may take to get a position. Getting ready Add three more sets of TextBlock controls under the longitude control for each of the following properties: Altitude, Speed, and Course. Set the speed label TextBlock Text property to Speed (mph). Name the TextBlock controls as you did for latitude/longitude so we can assign their Text properties from the code behind. The page should look similar to the following screenshot: How to do it... Perform the following steps to add altitude, speed, and course to the application: Open the code behind file for the page, and in the positionChanged handler, set Altitude in the same way as we did for latitude/longitude before; simply set the Text property of the txtAltitude TextBlock to the Altitude property as a string. For the Speed property, convert from meters per second to miles per hour. One meter/sec equals 2.2369363 miles per hour, so we can multiply the Speed property by 2.2369363 to get miles per hour. Display Course so that the normal users can understand it, using the name of the direction (that is, North, South, East, West). The Course value is a degree value from 0 to 360, where 0/360 is north and the degrees go clock-wise with a compass. Create a series of if statements that will provide the correct heading. Between 316 and 45 will be North, 46 and 135 will be East, 136 and 225 will be South, and between 226 and 315 will be West. Our _watcher_PositionChanged method is now as follows: void _watcher_PositionChanged(object sender, GeoPositionChangedEventArgs<GeoCoordinate> e) { txtLatitude.Text = e.Position.Location.Latitude. ToString() txtLongitude.Text = e.Position.Location.Longitude. ToString(); txtAltitude.Text = e.Position.Location.Altitude. ToString(); txtSpeed.Text = (e.Position.Location.Speed * 2.2369363). ToString(); double course = e.Position.Location.Course; string heading = string.Empty; if (course >= 46 && course <= 135) heading = "East"; if (course >= 136 && course <= 225) heading = "South"; if (course >= 226 && course <= 315) heading = "West"; else heading = "North"; txtCourse.Text = heading; } How it works... If you deploy the application to your phone now, you will see Speed display NaN (Not a Number) , Altitude display zero, and Course is blank. This is because Altitude, Speed, and Course are only available when you specify that you want high accuracy location information. We do this by instantiating the GeoCoordinateWatcher with a GeoPositionAccuracy type of GeoPositionAccuracy.High in the constructor. By default, the accuracy is set to GeoPositionAccuracy.Default, which only uses cellular triangulation and is not accurate enough to calculate speed, altitude, or course. GeoPositionAccuracy.High uses GPS and Wi-Fi, when available, which provides more accurate positions. Although it is more accurate, it also uses more power and can take longer to get your position. This is why High is not the default. It is strongly recommended that you only use the higher accuracy when it is absolutely needed. In this case, we need the Altitude, Speed, and Course, so it is necessary. Set the accuracy level to high in the GeoCoordinateWatcher constructor , like so: _watcher = new GeoCoordinateWatcher(GeoPositionAccuracy.High); If you redeploy the application to the phone, you may notice it still shows NaN for Speed. This may be because you are indoors and have an obstructed view of the sky or it may just take a few moments to get a good signal. Once you have a good GPS signal, you should see valid Speed, Altitude, and Course values. The best way to test this application is in the passenger seat of a driving vehicle so you can compare the vehicles, speedometer to the speed in the application. There may be times, as well, when you lose GPS signal. When this occurs, the latitude and longitude values will also be set to NaN. In such cases, you may want to give the user a friendlier explanation of the problem. You can simply check the IsUnknown property in the position changed event and provide a better message. For example: void _watcher_PositionChanged(object sender, GeoPositionChangedEventArgs<GeoCoordinate> e) { if (e.Position.Location.IsUnknown) { txtLatitude.Text = "Finding your position. Please wait ..."; txtLongitude.Text = ""; txtAltitude.Text = ""; txtSpeed.Text = ""; txtCourse.Text = ""; return; } txtLatitude.Text = e.Position.Location.Latitude. ToString(); txtLongitude.Text = e.Position.Location.Longitude. ToString(); txtAltitude.Text = e.Position.Location.Altitude. ToString(); txtSpeed.Text = (e.Position.Location.Speed * 2.2369363). ToString(); double course = e.Position.Location.Course; string heading = string.Empty; if (course >= 46 && course <= 135) heading = "East"; if (course >= 136 && course <= 225) heading = "South"; if (course >= 226 && course <= 315) heading = "West"; else heading = "North"; txtCourse.Text = heading; } The last property we will cover in this recipe is the Permission property on the GeoPositionWatcher. Before submitting your app to the marketplace, you must define which phone capabilities your app requires. One of those capabilities is location. Before a user installs an application, he/she is informed of the capabilities the app requires and must accept them to install. Even though the user has given the app permission to use location services of the phone, the user can still turn off location services for all apps from the settings menu. The Permission property will help us check for this and tell the user why the app isn't working. There is a slight trick though; the Permission property will be set to Granted when the watcher is first created, even if Location services are disabled in the Settings menu. It will be reset to Denied after the Start method is called. So we must check for a Denied permission value after calling the Start method. For instance: private void butTrack_Click(object sender, RoutedEventArgs e){ _watcher = newGeoCoordinateWatcher(GeoPositionAccuracy.High); _watcher.PositionChanged += _watcher_PositionChanged; _watcher.StatusChanged += _watcher_StatusChanged; _watcher.Start(); if (_watcher.Permission == GeoPositionPermission.Denied) tbLatitude.Text = "Please enable location services and retry";} We can test this by turning off location services. From the start screen, flick left to the App list, tap Settings, and then tap location. Swipe the switch left to the Off position. Redeploy the application to your phone, click the Start Tracking button, and you will see our new message. As mentioned previously, the user must accept the capabilities of the application before installing it. There may be future updates to the phone which allow the user to change the allowed capabilities of individual apps from the settings menu as well. The Permission property would also be useful in this scenario. There's more... You may have also noticed the CivicAddressResolver and CivicAddress classes in the System.Device.Location namespace . As its name implies, the CivicAddressResolver returns an address from a GeoCoordinate. Unfortunately, this is not yet implemented for Windows Phone. You can instantiate them and attempt to use them, but the returned CivicAddress will always be unknown. Hopefully, this will be implemented in the future updates of the operating system.
Read more
  • 0
  • 0
  • 2029

Packt
18 Feb 2014
5 min read
Save for later

XenMobile™ Solutions Bundle

Packt
18 Feb 2014
5 min read
(For more resources related to this topic, see here.) Introduction to XenMobile™ Solution The XenMobile Solution allows to manage mobile devices, the applications inside these devices, and the data in these applications. This enables users to access their apps, which may be mobile-, SaaS-, web-, or Windows-based from a universal app store. It provides administrators with a granular level control over the devices and manages them accordingly by implementing multiple security policies. It provides admins with the options to securely deliver productivity apps such as e-mails or intranet websites to end users. Also, it permits options to securely wrap applications before deployment without compromising application security and productivity. With more and more enterprises welcoming the Bring Your Own Device (BYOD) concept, a scenario where the employees are allowed to bring their own devices at work, XenMobile components allow admins to securely manage these devices without hampering the end-user device experience. In this section, we will introduce our readers to the following XenMobile Solution components and their role in the XenMobile Solution: NetScaler Gateway: This is a secure, access-control management solution allowing users to securely access internal resources. It also provides administrators with granular control policies to manage how devices will function once they are connected to internal resources. These internal resources can be an intranet portal, corporate e-mails, or in-house apps. XenMobile Device Manager: The XenMobile Device Manager allows administrators to manage devices, users, enroll devices, deploy applications and files, and set policies. XenMobile Device Manager also has the option to integrate Active Directory and detailed reporting features. App Controller: App Controller allows users to access the Web, SaaS-based applications, iOS and Android apps, and integrate ShareFile apps on their device from anywhere on an internal network. When integrated with NetScaler Gateway, the XenMobile Solution provides the users with access to these resources from an external network. Administrators have granular security policies to implement on devices connecting either from an internal or external network. MDX Toolkit: The MDX toolkit is a software that must be installed on Mac OS to wrap iOS or Android-based apps and ensures the apps are secure and compliant when installed on end-user devices. Administrators can also define a set of default policies while wrapping the app to limit how it works. Worx Apps: These are client-based apps that communicate with App Controller and allow users to access internal resources anywhere. They contain Worx Home for user enrollment, Worx Web to access web-based resources, and WorxMail for accessing corporate e-mails. ShareFile: This is a cloud-based, file-sharing service that enables users to securely share documents from different apps or access shared resources on a desktop from mobile devices. ShareFile data can be accessed as an app, web resource, or through integration with Outlook as an add-in. The XenMobile Solution with its components creates a highly secure and enterprise-compliant solution. The following diagram is a detailed network diagram for the XenMobile Solution provided by Citrix: © Citrix Systems, Inc. All Rights Reserved. XenMobile™ Solution features XenMobile contains some of the most sought-after features when compared to its competitors. In this section, we will list some of the features available in XenMobile, as follows: Configuring, provisioning, and managing mobile devices on Windows Mobile, Symbian, iOS, and Android platforms Mobile Content Management using SharePoint and network-driven integration Secure mobile web browser App-specific micro VPN Integrating Windows apps Unified app store Secure document sharing, syncing, and editing The deployment flowchart While implementing a Mobile Device Management (MDM) solution, it's very important to have a deployment pattern. This helps in understanding which components are required or are not suitable as per the environment needs. This brings in the requirement to have a detailed flowchart of the Solution deployment. The following diagram shows the Citrix-recommended best practice's deployment flowchart for the XenMobile Solution: © Citrix Systems, Inc. All Rights Reserved. Explanation In this section, we will break down the deployment flowchart to understand the component selection phase. The flowchart is based upon our requirements and will vary from one scenario to other. Phase 1 The essentials for phase 1 are as follows: Requirement: Do we want an MDM solution to manage the enrolled devices? Decision: If an MDM solution is required, then we proceed with the XenMobile Device Manager installation; alternatively, we can move to the next requirement Phase 2 The essentials for phase 2 are as follows: Requirement: Is application and content management required? Decision: If application and content integration is required then we can deploy the XenMobile Solutions Bundle; alternatively, move to the next requirement Phase 3 The essentials for phase 3 are as follows: Requirement: Will there be users accessing the integrated applications and data from the public Internet? Decision: If Yes, then move ahead with the NetScaler Gateway deployment; alternatively, move to the next requirement Phase 4 The essentials for phase 4 are as follows: Requirement: Is access to XenApp or XenDesktop required? Decision: If Yes, then connect using StoreFront Summary This article provided a brief overview of XenMobile Solution and each of its components. We also covered many of its features that make it unique and the Network architecture of the solution. Additionally, we have addressed the best practice deployment flowchart of the XenMobile Solution as recommended by Citrix. Resources for Article: Further resources on this subject: So, what is XenMobile? [Article] Gesture [Article] Creating Quizzes [Article]
Read more
  • 0
  • 0
  • 1966

article-image-interfacing-personal-information-management-pim-applications-blackberry
Packt
13 Aug 2010
17 min read
Save for later

Interfacing with Personal Information Management (PIM) Applications in BlackBerry

Packt
13 Aug 2010
17 min read
(For more resources on BlackBerry, see here.) The BlackBerry handhelds come pre-loaded with many great programs to help make a person more productive. While messages may be the most common reason a person will purchase a BlackBerry, the other Personal Information Management (PIM) applications often quickly become essential as well. Not only can you interface with these applications by adding or editing content in them, you can also listen for events that allow you to react to things that happen. Some of the applications even allow you to add menu items and other "active content" to them. That's a lot to talk about, so we'll just focus on some of the most common tasks to get you started in this article. As a developer, you cannot ignore the other applications on the handheld. The more integrated an application can be with these standard applications, the better the user experience will generally be. Our TipCalc application is very specialized, and one of the few that works well without integrating with other applications. More often than not though, any applications that you create will benefit from some level of integration. Introducing PIM The first area that we will take a look at is the Personal Information Management, or PIM applications and data. PIM applications are a rather generic name for a group of tools that manage your personal information, especially as it relates to your handheld. This could be stretched to include a lot of things, but it generally means your messages, contacts, and scheduling information that help you to manage your life. In BlackBerry terms it means the Messages, Address Book, Calendar, Tasks, and Notes. Access to the PIM data in the BlackBerry SDK is provided through the JSR-75 specification, which is a Java standard. Like many of the Java standards in the BlackBerry SDK, there are also BlackBerry-specific extensions available that expand the basic classes with new BlackBerry-specific functionality. Like many of the other standards we find in Java, JSR-75 implements a factory pattern where one class, in this case the PIM class, is used to create objects for the other more specific types of PIM data. The PIM class can basically do only one thing and that is to retrieve a PIMList object that contains a bunch of specialized PIMItem objects. Why is all so generic? All of these PIM classes may seem very generic and you would be absolutely correct. They are generic and they are supposed to be that way. PIM data is a very generic concept so the implementation is very generic as well. Also, because it is a Java standard, it needs to be flexible enough to accommodate any system that it might be implemented on. A perfect example of this kind of flexibility is the BlackBerry PIN field. The BlackBerry PIN is an entry in your address book and therefore, it should be included in the PIM data that you get. However, a PIN is a BlackBerry-specific concept and no other device out there will use it. You can't really expect the Java standard to include specialized fields for every possible piece of data that some device may have or want to include. The answer to this is to present PIM data in a key-value pairing so that it is flexible enough to handle every possible scenario. A key-value pairing is a somewhat technical term to describe the pattern for storing values based on a static key. Or, more simply, if you know the proper key you can access the value. The flexible part is that the PIM object storing all of the values does not need to know about each specific value or provide any special mechanism for accessing each specific value. All access is done through generic methods, which also require the key. The difficulty in using this kind of approach is that the keys must be common knowledge. In addition, simple numeric keys do not support self-documenting code or even easily readable code. Keys that are string values offer a lot of advantages—in that the keys are much more readable, but the possibility for mistakes is very great because you don't have the compiler to help ensure that only correct keys are used. To help solve these issues there are derived classes for each type of PIM item. While you can do nearly everything by using the generic classes that a derived class would offer, I wouldn't recommend it. These classes are here to make your code easier to write and read, and should be used. PIMLists As we said early on, the PIM class is used primarily to retrieve a PIMList object for a specific kind of PIM item, that is, address book contact, calendar event, and so on. For each of these types, there is also a specialized class that you can use instead of the generic PIMList class. Classes such as ContactList, EventList, and ToDoList offer a specialized version of the more generic PIMList class. These specialized classes are also part of the Java standard and should be preferred because they offer a few more methods which are specific to that kind of data. There are BlackBerry-specific versions of these classes as well. Therefore, the BlackBerryContactList class is the BlackBerry-specific version of the ContactList, which is in turn a specialized version of PIMList for contact data. Generally speaking, you will want to use the BlackBerry-specific versions of PIMList classes when making your applications. PIMItems A PIMItem is the generic representation for any piece of PIM data. Just like there are specific versions of the PIMList, there are also specific versions of the PIMItem class for each kind of PIMItem. Contact, Event, and ToDo are all specific versions of a PIMItem for that kind of PIM data. As you might expect, there are BlackBerry-specific versions as well. BlackBerryContact, BlackBerryEvent, and BlackBerryToDo all exist to extend and further specialize the standard Java classes. These specialized classes aren't as specialized or easy to use as one might expect though. Providing a method called getFirstName might be really useful, but unfortunately, you will find nothing of the sort. The specialized classes offer few methods for accessing data. Instead, they provide static values for the keys used to set and retrieve data from the PIMItem class. Remember, earlier we noted that one drawback to using this kind of key-value pairing was that keys were sometimes not clear and that you could not expect help from the compiler. By providing each key value in the specialized class, both of these goals are accomplished. The name of the key value now provides a readable name and the compiler will flag an error if there is a typo or problem with the constant value being used. Another aspect of PIMItem is that each value that an item has a specific type associated with it as well. Some of these are obvious, such as the start date of an event using a Date type. Some of them, such as the Name field of a Contact that requires an array, are not. Some fields can be given a subtype as well, such as the Phone field. With the subtype you can specify what kind of phone number it is: home, work, or mobile. Furthermore, some of the fields can have multiple occurrences while others cannot. A good example of this is the Email field in a Contact. A contact is allowed to have up to three e-mail addresses, but there is no subtype associated with them like there is with phone numbers. The bottom line to all this is that the PIM items have a defined structure to them and they won't allow just any value to be put into a field. The documentation plays a big role here in understanding this because there are no field-specific methods to provide some additional assistance in the proper way to access each field. Laying the ground work Still, this is all rather abstract because you haven't seen any real code samples yet, so let's get into some code! For this article, you will build an application that someone will use to request some time off from their manager. This is definitely one of those applications that just can't be done without interfacing with other applications on the handheld! To make getting started a little easier we will take the starter TimeOff application from the code bundle and add to it throughout this article. The first task to undertake is one to help make testing and debugging easier. Remember, you will be working on the simulator, which is essentially a brand new device and which can be often reset. That means you don't have any of your contacts there! You will need some contacts later, so to get started let's add a menu item to the application that will create a few contacts that you can later use to test with. Time for action - creating test contacts Modify the _AddTestAddressesAction menu item in the TimeOff project to look like the following completed code. protected MenuItem _AddTestAddressesAction = new MenuItem( "Add Test Data", 800000, 50){ public void run() { PIM pimInstance = PIM.getInstance(); try { // TODO: Create test contacts BlackBerryContactList contacts = (BlackBerryContactList)pimInstance.openPIMList( PIM.CONTACT_LIST, PIM.READ_WRITE); BlackBerryContact newContact1 = (BlackBerryContact)contacts.createContact(); BlackBerryContact newContact2 = (BlackBerryContact)contacts.createContact(); String[] names = new String[contacts.stringArraySize(BlackBerryContact.NAME)]; names[BlackBerryContact.NAME_FAMILY] = "Smith"; names[BlackBerryContact.NAME_GIVEN] = "John"; if (contacts.isSupportedArrayElement(Contact.NAME, Contact.NAME_SUFFIX)) { names[BlackBerryContact.NAME_SUFFIX]="Jr"; } newContact1.addStringArray( BlackBerryContact.NAME, BlackBerryContact.ATTR_NONE, names); names[Contact.NAME_FAMILY] = "Doe"; names[Contact.NAME_GIVEN] = "John"; if (contacts.isSupportedArrayElement(Contact.NAME, Contact.NAME_PREFIX)) { names[Contact.NAME_PREFIX] = "Dr."; } newContact2.addStringArray(Contact.NAME, Contact.ATTR_NONE, names); //TODO: Add Phone numbers //TODO: Add Email Addresses //TODO: Add Addresses newContact1.commit(); newContact2.commit(); } catch (PIMException e) { // TODO Auto-generated catch block e.printStackTrace(); } }}; Then add this line to the constructor to make the menu item available when you run the application. this.addMenuItem(_AddTestAddressesAction); What just happened? This is the first of several baby steps as you work towards the goal of creating some test contacts in the address book in the simulator. As the address book in the simulator doesn't have any entries to begin with, and can be erased frequently, doing this provides you with a way to quickly and easily create or recreate the contacts you will use later on for testing other parts of this application. It also happens to be a great way to demonstrate how to add contacts. This first baby step does only a few things. First, it gets a PIMList object for contacts and then creates two new contacts. After this it sets the name of each one and finally commits the records into the address book. These steps make sense at a high level, but let's take a look at the details. The first step is to get an instance to the PIM object, which is done through a static method in the PIM class called getInstance. PIM pimInstance = PIM.getInstance(); Once you have an instance of PIM, the next step is to get a list of contact items using the openPIMList method on the instance you just retrieved. This same method is used to get a list of any kind of PIM item so you must specify the type of data to get as one of the parameters. The PIM class offers constant values for every kind of PIM item, so in this case, use the constant PIM.CONTACT_LIST. As you plan to add new contacts, the next parameter needs to be the constant PIM.READ_WRITE so that you have write permissions. It's always good practice to request the minimum amount of permissions that you need, so if your application doesn't change or add data to the list you should simply use the PIM.READ permission. As we touched on earlier, this method returns a generic PIMList type so you also have to cast it to the appropriate specialized type. If a list type of CONTACT_LIST has been specified, you can cast the resulting PIMList to either of the available specialized classes—ContactList or BlackBerryContactList. As long as your application is a BlackBerry-specific application, there is no good reason to use the less specialized class of ContactList. Instead, you should always use BlackBerryContactList. BlackBerryContactList contacts = (BlackBerryContactList)pimInstance.openPIMList (PIM.CONTACT_LIST, PIM.READ_WRITE); The next step is to create a couple of new contacts that you will start to populate. This is done through the createContact method available on the ContactList class. Again, you need to cast the resulting objects to the proper type. The createContact method returns a contact, but again you've chosen to use the more specialized version of BlackBerryContact instead. Because this is all being executed on a BlackBerry handheld, you can always cast a contact to a BlackBerryContact safely. The same is true for each of the Java specialized classes and their corresponding BlackBerry specialized class. BlackBerryContact newContact1 = (BlackBerryContact) contacts. createContact();BlackBerryContact newContact1 = (BlackBerryContact) contacts. createContact(); The next segment of code sets the name attribute of the newly created contacts. Notice that this is done through an array of String objects instead of individual methods. This isn't something that is done to be more efficient, it is done this way because it must be; there is no other way. We mentioned before about each field in a PIMItem having a type associated with it. Most of the field types are basic String or Date type fields, but NAME is more complicated than most of the other fields. The NAME field is defined as a StringArray because there are many parts to a name and you want to be able to set each part separately. There aren't very many fields of this type used, but this is probably one of the most important. You can only set the NAME field as a whole unit, so if only one part of the name needs to be changed the entire name field must be replaced. To work with the name, you must first create a string array of the proper size. There is no constant value for this as it may vary with the SDK version. Instead, you must first get the size by using the stringArraySize method on the ContactList and then construct a new array by using the returned value. String[] names = new String[contacts.stringArraySize(BlackBerryContact.NAME)]; Once you have an array of the proper size each part of the name is set by indexing the array by using the NAME constant from the Contact class. names[BlackBerryContact.NAME_FAMILY] = "Smith";names[BlackBerryContact.NAME_GIVEN] = "John"; In this example, you also want to add another name part but are not sure whether the field is supported in this system. Not all fields are supported and not all of the name subfields are supported either. You can test to see whether a field or a subfield is supported by using the isSupportedField or isSupportedArrayElement methods in the ContactList class. In this case, you test to see if the suffix is supported, and then set the suffix if so. if (contacts.isSupportedArrayElement(Contact.NAME, Contact.NAME_SUFFIX)){ names[BlackBerryContact.NAME_SUFFIX]="Jr";} This step is very important if you want to use the same code for multiple platforms. Each system can support the fields it chooses. In this case, the suffix is NOT supported and if you were to step through this code in the debugger, you would see that the code to set the suffix is skipped over. Later on, when you test this application, you will also see that the suffix was not added to the contact. Other platforms may implement it differently. You could just assume each of the name subfields are supported and set the field without testing to see if it is supported. In the BlackBerry SDK, unsupported fields are just quietly ignored. This can lead to confusion wondering why a field doesn't appear in the Address Book application, but it won't cause an error. The next step is to actually add the NAME field to the contact. Up until this time you've simply been building an array in memory with all of the proper values. newContact1.addStringArray( BlackBerryContact.NAME, BlackBerryContact.ATTR_NONE, names); Notice that the method addStringArray doesn't give any indication about what field is being added, but only what type of data is being added. All of the PIMItem methods are like this. Remember, this class is designed to be generic. The first parameter is the field indicator, which is one of the many constants that are defined in the Contact class. In this case, we use the BlackBerryContact class. Because BlackBerryContact derived from Contact, all of the constant values are accessible. The BlackBerryContact class does define some constants that are BlackBerry-specific, such as PIN. For this field you must reference the constant value from BlackBerryContact because the Java standard Contact class does not define it. Partly for this reason, I suggest always referencing constant values from BlackBerryContact because all of the constant values will be available through this class. The method addStringArray was chosen because that is the type of data that you are adding. The NAME field is defined as a string array and so you must use the addStringArray method because it corresponds to the data type of the field. Once you finish with the first contact, the code starts building the NAME string array to add a second contact. For demonstration sake, all of the constant values that are referenced are done so using the Contact class instead of the BlackBerryContact class. names[Contact.NAME_FAMILY] = "Doe";names[Contact.NAME_GIVEN] = "John";if (contacts.isSupportedArrayElement(Contact.NAME, Contact.NAME_PREFIX)){ names[Contact.NAME_PREFIX] = "Dr.";}newContact2.addStringArray(Contact.NAME, Contact.ATTR_NONE, names); Also, notice that the second contact applies a prefix to the name and tests to see if it is supported in the same way as you did for the suffix when adding the previous contact. However, the prefix is supported and if you were to step through this method in the debugger, you would see that the prefix is being set properly. The last step you have to do is to commit the data that has been added to the contact. newContact1.commit();newContact2.commit(); Simply creating a new contact is not enough; you must commit the changes in it by using the commit method. Creating a contact and then never committing it will not have any effect on the Address Book application. It simply won't be shown in the list. That's the whole point of this exercise, so you have to make sure and commit the changes once they are all done. At this point, if you were to run the application and select the menu, you would see two new contacts added to the Address Book application in the simulator. They would show up as Dr. John Doe and John Smith. There would be only names with these contacts because that is all that you've added so far. In the example code that you just stepped through there was one mistake that could have proven to be very serious. Did you catch it? You are reusing the names array to set the names of both contacts. This is actually risky, but it happens to work out in this case. If the SUFFIX field had been supported then your Dr. John Doe would have actually been Dr. John Doe Jr. because the array was not reset before it was used again. If you had changed the order around, John Smith would have been Dr. John Smith. This might have lead to a bug that could have been tough to track down, so keep it in mind.
Read more
  • 0
  • 0
  • 1889
Unlock access to the largest independent learning library in Tech for FREE!
Get unlimited access to 7500+ expert-authored eBooks and video courses covering every tech area you can think of.
Renews at $19.99/month. Cancel anytime
Modal Close icon
Modal Close icon