Software Engineering of a Geospatial Video Database and iPhone Application John McCoey Advisor: Dr. Thomas Way Completed: Summer 2010 This Independent Study final report is submitted in partial fulfillment of the requirements for the degree of M.S. in Computer Science Department of Computing Sciences Villanova University Villanova, Pennsylvania U.S.A. ABSTRACT Geospatially tagged media can be an extremely useful source for understanding and virtually exploring a given location with more detail than a map alone can provide. Currently, there is a large assortment of applications in the iPhone App Store which offer the ability to tag images with coordinate-based location metadata. This metadata gives users the ability to search for images which may be of interest based on location. However, while both images and video can be captured from the iPhone, there is no such available application for video media. The YouTube API can tag geospatial locations to videos; however most videos found currently on the site are improperly tagged, and are therefore cannot be applied in any useful manner. Using the agile software engineering approach, I have planned, designed, and implemented a geospatially tagged database which allows for the uploading and searching of media captured from iPhone devices. Because all media in the database originates from the GPS enabled iPhone, the user is ensured the proper geospatial reference information is available. This study will focus on software engineering a prototype to a fully developed system from the research and planning stages through design, implementation, and testing. i ACKNOWLEDGEMENTS I would like to thank Dr. Way of the Villanova University Computing Sciences Department for his help and guidance throughout my Independent Study. ii CONTENTS Introduction 1 Chapter 1 Research and Design 1.1 Sprint 0: Ramp-up 1.2 Objective C 1.3 Database 1.4 Setup 1.4.1 WampServer 1.4.2 Subversion 1.5 Application Design 1.6 Database Design 1.6.1 Database Creation 2 2 2 2 3 4 4 5 5 6 Chapter 2 Development 2.1 Sprint 1 2.1.1 Sprint 1 Issues 2.1.2 YouTube Objective-C Library 2.2 Sprint 2 2.2.1 Linking the GData Project 2.2.2 Side Channel Approach 2.2.3 Location 2.2.4 Insert PHP 2.2.5 Search PHP 2.2.6 Search and Map Pages 2.2.7 Map Pins 2.2.8 Video Playback 7 7 7 8 8 8 9 9 10 10 11 12 13 Chapter 3 Wrap up 3.1 Sprint 3 3.2 Testing Results 3.3 Future Work 14 14 14 15 Conclusion 16 References 17 Appendices 20 iii INTRODUCTION The main goal of this research is to design and create an application using the Apple iPhone SDK. The application will both record and displays geospatially tagged media in a manner which enhances the overall value of the data. Additionally, we will look at different databases’ handling of geospatial indexing and searching, all while using an agile approach to Software Engineering. Geospatially tagged media is a form of standard media which has some information about its location, or geospatial information, associated with it. Geospatial information can refer to a single latitude/longitude coordinate, or some form of a wider area, generally made up of a group of coordinates. In more advanced examples, a geospatial tag may take into account the altitude, heading, and other spatial variables to determine the location of an object. With countless new smart phones, such as the Apple iPhone, becoming more prevalent among cell phone owners, users constantly have access to the internet and endless data about the world surrounding them. The most influential aspect of these smart phones is the way in which users can share data amongst themselves, making observation data more available and useful than ever before. The location where data is recorded immediately gives background information to the media. There are two main scenarios that drive the idea behind the application we are designing. The first is a user who is interested in a certain area, whether it is somewhere they currently are, or another location they are interested in, and would like more information about it. This is where past images, videos, and other media recorded at a given location can give the user a better picture of the area than a map. The second scenario is the exact opposite, where a user looks at a certain video, and wants to know more about the environment in which it was captured, or find more similar videos based on that location. Our single application aims to solve both of these problems. In order to ensure completion of at least a prototype application, our project needs detailed designing and planning. However, due to the nature of the research and a lack of knowledge of the existing technologies, we need the ability to change and adapt quickly to any problems or design changes. The Agile Method to Software Engineering [1] promotes a quick start with constant redesign to ensure a working application. To make an application for the iPhone, a developer must use the iPhone SDK, which runs through Apple’s XCode IDE, using the Objective-C language [2]. This is our first experience with the language, and we will spend a good amount of preparation time just learning the basics of the language. The most important aspect of any of the media we capture in relation to this research is its location. Therefore, we must make sure to choose a stable database which can quickly and accurately handle geospatial information. This decision, as well as research into which other technologies would be best suited for our needs, and the basics of the Objective-C language, starts the preparation step of our research. 1 CHAPTER 1 Research and Design 1.1 Sprint 0: Ramp-up When we decided to write an application, the iPhone was an easy choice for two reasons. First, we already have the hardware required to develop and test the application, and secondly, the iPhone is one of the fastest growing and most popular application markets right now. We begin our project by outlining the proposal and creating a website with a rough outline of our schedule, split into four sprints, available at http://csc.villanova.edu/~jmccoey. As stated before, we are following an agile approach to software engineering, and therefore our focus is more on implementing a working product than on full up front software design. We still need to plan accordingly, but are ready for any changes ahead. For the first RampUp Sprint, we are following the schedule shown in [Appendix A]. 1.2 Objective-C Because we have no prior experience with application development for the iPhone, we start on the project by researching and learning the basics of the language and the specific skills we will need for the application. We start by following the first few chapters of Sams Teach Yourself: iPhone Application Development [3]. Because we know the application will have to include location services and video playback, we are focused more on the chapters later in the book which apply to those topics. Objective-C is an object oriented language specifically used for application development on the Apple Mac OS and iOS, the iPhone operating system. The iPhone uses a special Cocoa Touch API within the Objective-C languages for generating and handling a graphical interface for user input. It is an expansion upon the C language, and accepts C code as valid syntax. This means a programmer must control memory management, given that object variables are pointers which can quickly fill the iPhone’s memory if not properly released [4]. While the Cocoa API makes the user interface very simple to design within Xcode, some of the intricacies left over from the C language give Objective-C a very steep learning curve. Objective-C can be downloaded for free, along with the Xcode IDE, however it can only be run on Apple Mac OS X. In addition, there is a $99 yearly fee to join the Apple Developer Program, which is required to deploy an application to any Apple device. It is the only way to get an application onto an iPhone, including a personal iPhone used solely for development and testing purposes. 1.3 Database Selecting Objective-C as the main language for the application is not much of a choice, beyond the initial decision to develop for the iPhone. However, we must decide between many different databases, all of which have distinct advantages and disadvantages. 2 Some of the most popular database systems include Oracle 11g, MySQL, SQLServer, and PostgreSQL. All of these databases support geospatial indexing, in various different ways, and each would be more than sufficient for our application’s needs. Oracle 11g Enterprise Edition is one of the strongest, and one which we have used before in other development projects. The Express Edition of Oracle is free, except the geospatial functions of 11g are not included. MySQL, which was recently purchased by Oracle, is free and supports more than enough geospatial functions to complete our research. While MySQL cannot handle some of the more complex features of databases, the general insert and select statements we are going to be using, were built for speed. We will use the MySQL database because it has all the features we need, and is extremely fast, while remaining very simple and easy to use. There are several ways to create geospatial objects in the MySQL database, but perhaps the most elegant, especially for single coordinate points, is the Well-Known Text, or WKT, string format. WKT is a standard string format regulated by the Open Geospatial Consortium to display geographic points, polygons, linestrings, and more in simple plain text [5]. In MySQL, a spatially indexed column of GEOM objects can be populated using the GeomFromText(WKT) method. A valid WKT is written as follows: POINT(longitude latitude) POLYGON((long1 lat1,long2 lat2,long3 lat3,long4 lat4,long1, lat1)) The longitude always comes before the latitude as it follows the (x, y) coordinate plane, where the x value is longitude and the y value is latitude. For a single point, only a space separates the values of the coordinate. The same is true for each coordinate of a polygon, with a comma separating each of the corner points, and the first point repeating at the end to close the polygon. 1.4 Setup Since we have decided on a database, the next step before coding the application is setting up the systems and environment we will be using to develop and host the project. We do not have access to a dedicated server, and must use our own system to host the database and server. Therefore, our entire system environment consists of three components. The first, and most obvious, is the iPhone itself, which will host the application. The iPhone we are using is a 3GS model, running the new iPhone operating system, iOS4. iOS4 was released in the middle of our application development, so we needed to upgrade our SDK and Xcode IDE at that time. This initially caused a few problems with memory management and project references, but after reinstalling Xcode, we were able to make the change. Our application will be written and compiled within the Xcode IDE on our second system, a Mac Mini running Mac OS X Snow Leopard. The OS X system can host our MySQL database as well, but we are opting to use for a third Windows 7 PC instead. This is mostly because we are more familiar with configuring the network and system settings within the 3 Windows operating system. Due to our unfamiliarity with the operating system, we want to limit our OS X usage to the minimum necessary Xcode development. 1.4.1 WampServer In order to easily create and have full access to a MySQL instance, we choose to download and install WampServer 2.0. Wamp stands for Windows Apache MySQL PHP, and is available as a free download under the GPL license [6]. Once installed, we can create a quick temporary database using the included phpMyAdmin tool to familiarize with the system. The problem with hosting our own database on a non dedicated server is that the dynamic IP address of our router will unpredictably change over time. To handle this, we must do two things. First, we will register with DyDNS to create a dynamic DNS hostname which forwards all requests to our router’s IP address [7]. DyDNS allows us to create the site http://mccoey.selfip.net to always refer to our WampServer system. We need to make a few changes in our local wireless router to maintain the correlation between our URL and router IP address and to enable access from outside the network. The Linksys E1000 router which we are using has an option for DDNS, or Dynamic Domain Name System, in order to keep track of our IP Address. After setup, whenever the external IP address for our router changes, a notification is sent to the DyDNS site to update the reference from the URL http://mccoey.selfip.net to the correct new IP address. This ensures we constantly have access to the router at that location. Secondly, once any request reaches the router, it needs to be routed to our Windows 7 PC, and not any of the other systems connected to the wireless router. By assigning the Windows 7 host environment a static IP address within the local area network adapter settings, we can use the Port Forwarding feature of our router to ensure all requests of a certain type are directed to the Windows 7 System and can reach our WampServer and MySQL database. Within the wireless router configuration, we forward the ports 8080 and 3306, for Apache Server and MySQL, respectively, to the Windows 7 system. 1.4.2 Subversion Although our development team consists of only one person, it is still important to maintain updates, changes, and the latest code revisions in subversion. Luckily, most of our code will be written in the Xcode IDE, which contains its own built in Subversion client. For the small amounts of PHP code, as well as any diagrams and documentation from our WampServer, we will use the free open source program Tortoise SVN [8]. These subversion clients must point to a subversion repository. One of the easiest repositories to use is one maintained by the open source site SourceForge.net, although it requires some time for a repository to be approved after creating a new account. To avoid waiting, we are going to create a new folder to house our project on an existing SourceForge repository we previously created and used for another class [9]. 4 1.5 Application Design Now that the setup of all of our systems is completed, we are ready to focus on the application and database design and implementation. Based on the requirements we laid out for the iPhone application, we designed three separate use cases for our entire system, found in [Appendices D, E, F]. Each one of these diagrams a system architecture for how the application will react to a user uploading media, a user searching for media on the map, and a user playing back or viewing the media found on the map. For the application, we create a design which includes three pages; one to handle input of media, one for search options, and finally one with a map or globe display. There is no necessary order for the user to view the different pieces of the application, and each will be accessible at all times. The first page we will work on, and therefore the first we design, is the page which allows a user to upload a video or image to the database. The upload page requires four pieces of information: the name of the media, a description, the media itself, and the current location. At this time, we are choosing to select only the current location at the time of upload, and to leave any option to select a location for a previously recorded image or video for a future iteration, therefore that is not in our design. For the search options page and the map page we will create temporary placeholders in our design. We have a general idea of how they will work, although at this time we have not fully developed the design and style. Figure 1.1 1.6 Database Design We next design our database system using a rough ER Diagram, shown in Figure 1.2, with options for future expansion of our application. The motive is that multiple users will have access to this application on their iPhone, each having an individual username specifically for MediaMap, our application. Each user is also associated with one or more account entries which store a user’s external usernames and passwords for various sites, such as YouTube. 5 Figure 1.2 Based on this design, a user can also add other users as a friend. Each user media entry in the database is associated with the user who uploaded it. Any media uploaded by the user has a location and a type, at this time either photo or video. 1.6.1 Database Creation To create the database, we simply use the phpMyAdmin tool included with WampServer. This lets us manually add tables to a new database to create this format. An image of our completed database is listed in [Appendix G]. When creating the location table, we must create a geospatial index on the location column. To do this, we select the column GEOM type, which will accept all forms of WKT geometries [10][11][12]. While we currently support only single points for the location of media, we wanted to leave open the option for line strings or polygons. These could be particularly useful for video which may have been recorded over a series of location, rather than a single coordinate point. These geometries may be particularly useful for video which was recorded over a series of locations, or while traveling, rather than a stationary point. 6 CHAPTER 2 Development 2.1 Sprint 1 The first development sprint follows the schedule found in [Appendix B]. The first few tasks scheduled in this Sprint are remaining tasks from the Sprint 0: Ramp-Up phase of the project, which was not fully completed on time due to some difficulties in the initial database and port forwarding setup. These tasks took longer than expected to finish, and consequently pushed other tasks back. The goals of Sprint 1 are to wrap up the remaining Sprint 0 tasks and create the upload segment of the application. At the end of this sprint, we hope to select an existing image or video from the iPhone Photo Library or capture a new video or image and upload it into our database. Because there are already several available applications which map the location of images from the iPhone, we decided to start with videos. The initial design shows that we will encode the iPhone video to Base64 and send it through an HTTP POST request to the PHP server [13]. From the server, the PHP YouTube API uploads the video, and returns the resulting video URL [14]. At this point, the URL will be inserted into the database’s Media table, along with the user id, location, and other video information. As stated earlier, for the location, we are currently using only the iPhone location data available at the time of upload. The user interface is created very easily using the Xcode Interface Builder, which is by far our favorite part of using the Xcode IDE. It quickly lets you add and configure any number of interface components and effortlessly connect them to outlets in the back end code, and took only a few minutes to learn. 2.1.1 Sprint 1 Issues Unlike the Interface Builder, however, we have several problems using the Objective-C language itself to develop the back end of our application. It took much longer than expected to learn the language, and even still requires looking up almost every line of code in the API [15]. A lot of the difficulties we are encountering within the Objective-C language come from its roots in the C language, such as the existence of pointers, and a lack of an automatic garbage collection. Also, the long syntax and confusing variable declarations, instantiations, and method calls make it difficult to guess which methods should be called, and how to find new methods. As easy as it is to complete the user interface, and even to program it to select and capture media, getting that media into a variable which could be converted to bytes is much more difficult. Once we get a mutable object, we still have trouble using a Base64 Encoder class to get the data from the iPhone to our PHP server [16]. At this time, the two week Sprint is coming to a close, and we still do not have any way to get the media we are capturing from the iPhone to the PHP server. 7 2.1.2 YouTube Objective-C Library As we search for more information on how to upload data to the PHP server, we discovered that the YouTube API is available in Objective-C as well. It does not have much documentation, but looks like it allows for a direct upload from the iPhone to YouTube. This eliminates the need to send any encoded data to the PHP server, and we can pass along the URL instead [17] [18]. 2.2 Sprint 2 In Sprint 2, we have to redesign our overall schedule to account for the issues we ran into in Sprint 1. A few requirements of our application change to use the YouTube Objective-C library instead of passing the bytes to the PHP server for uploading videos. As we mentioned earlier, uploading images to Flickr was really a secondary task, and in order to get a working prototype, we are going to abandon the images portion for the current version. However, we will leave the user interface for selecting images as well as the code for uploading media using Base64 Encoding and PHP simply commented out in the code for future development. The schedule for this sprint, found in [Appendix C], has been modified to make sure that we will complete a working prototype at the end of the Sprint. As this is the last full development sprint, with Sprint 3 reserved for testing and improvements, we must ensure that the most important aspects of the application which demonstrate uploading and searching for videos are completed. 2.2.1 Linking the GData Project With this redesign, we first add the Google Data API to the Objective C code. There are two ways to do this; the first is to link the project to the iPhone Static library, and the second is to compile the source files directly into the iPhone application [19]. The first option, to statically link the two projects, is the most efficient, as it requires less space and compilation time for the iPhone application. We try to link the two projects, but almost immediately run into problems when the entire project will not compile. We are unsure of the reason, as it may have been some environment variables, but it will not allow us to continue. Instead, we follow the second method of compiling the code directly into the iPhone project. This will increase the amount of code to be moved to the iPhone as well as the compilation time, but includes only the parts of the API which we need. After several trying to add the library several times, we finally got the code to compile and start to work on uploading videos. However, the documentation for the Objective-C version of the API is not very complete; including only a single example file of how to get the upload to work. After several more days of trying, we have wasted too much time trying to get the videos to upload, and need to move onto another option. 8 2.2.2 Side Channel Approach In an effort to complete the project on time, we eliminate the upload functionality of the application. Instead we quickly include another text field between the name and description fields which holds the end of a YouTube URL. A URL link to every YouTube video is standard formatted as http://www.youtube.com/watch?v=ID, where ID is the unique identifier for the given video. Because the beginning of the URL is always the same, the unique identifier is all that we need to store in our database. It will also make it easier if YouTube ever changes the format of the URL, as we will only need to change it in one location, on the playback within of our application. The iPhone’s camera application natively features the ability to upload videos to YouTube, and because this is not a part of the research we are trying to prove, we utilize that built-in function to upload a video captured outside of MediaMap to YouTube. Once the video has been uploaded, we follow the “Share video with friends” link to see what the full YouTube URL looks like. At this time, we copy the Figure 2.1 unique video ID, open our MediaMap application, and paste the ID into our new text field. By doing this, we eliminate the need to upload the videos from within the application, and instead can pass the information from the upload page on to our PHP server as a unique text id. 2.2.3 Location When the user clicks submit on the upload page, the MediaMap application gets the current location, formats it as a WKT POINT String, and forwards it, along with the name, media type, description, and YouTube link to our PHP server. To get the location using the iPhone, we must be running the iPhone’s Location Manager device. The Location Manager can be initialized with different settings to control how often the location is updated, and how accurate the resulting coordinate is. We use the most accurate location type, and save the latitude and longitude every time an update is received. This process of updating location starts as soon as the application loads. 9 If it is the first time the user has opened the application, they are prompted with a dialog box asking for permission to use the location services, and a purple arrow will appear in the status bar to indicate the GPS is active. When the user clicks the “Upload Media” button, the most recent coordinate is converted to the POINT(longitude latitude) string format, and sent with the rest of the data as parameters to an HTTP GET request [20]. 2.2.4 PHP Insert Within the PHP WampServer on our Windows 7 system, there are two files, insert.php and search.php, allowing a connectection via a mysql_connect statement to our database. We then create and execute two INSERT SQL statements [21]. The first satment inserts the video into the Media table. This creates a new unique media id number and adds the user id, which at this time is only our single user, and therefore always 1, the link, name, date, size, description, and type. Because we uploaded outside of the application and therefore do not know any statistics about this video except for the form filled out by the user, we enter 0 for the size and cannot insert the length, rating, or thumbnail, which are all left as null. When the data is inserted into the Media table, it returns the unique media id created for that row. That id is then used to record and associate the location of the media in the Location table. The media id is inserted and uses MySQL’s GeomFromText method to create a MySQL GEOM object from the WKT String. Because the Location table is geospatially indexed, we will later be able to quickly search all media based on location [10]. 2.2.5 Search PHP The search.php page is a bit more complicated than the insert.php page, although was written using only one advanced SQL SELECT statement. Again using mysql_connect a connection to the database is created, and a SELECT statement is executed to get the videos which meet our search requests. The PHP returns the results to the requestor in basic XML format [21]. This XM response will be parsed on the iPhone to determine the location and information for all found media. The search.php parameters consist of only the bounding box of the search area as a POLYGON WKT String and the media type we are searching for; in this case ‘VIDEO.’ Any other search criteria could be easily added later with a modification to the PHP parameters and SELECT statement. The SQL SELECT statement we create searches based on location by using the MySQL MBRContains method which returns 1 if a GEOM is within a given bounding box. By providing the bounding box of the visible area of the map, we find the locations within the visible area. The SQL statement selects the media information of all media from the Media table by using a JOIN with the Location table based on the unique media id fields. Each row of data is transformed into an XML entry and sent as a whole back to the iPhone application [10][11]. 10 2.2.6 Search and Map Pages The Search Options and Map pages were not designed prior to this Sprint, and so we must now design and create them at the same time. The Map page is simple in that it only contains exactly what its names states: a map. On the other hand, the Search Options page lists the set of all available options for a user query. In order to complete this page, we first define what those searchable options are. Because we ran out of time due to the problems of earlier sprints, we must adapt so that our application handles only one type of search, to return all videos based on location. However, we still design and create the Search Options page through Interface Builder to visualize what options a future iteration may have. Figure 2.2 This Search Page shown here is included in the current version of the application, although there is no code behind any of the interface components to change search options. It is merely a placeholder as an idea of how the final application may function. The options we include allow the user to decide if they want to search for all media, or just media available within the current view area. This will be more useful in a future iteration when there is another way to view the media besides the map, such as a table or list. The user will also decide if they want the search to include videos, photos, or both, and will be able to list keywords to narrow the search. The bottom section allows the user to select if they want to see only media they personally uploaded, or media uploaded by friends, all users, or any combination of choices. This again is simply another way to narrow a search to meet a user’s particular needs. 2.2.7 Map Pins Once the Insert and Search PHP pages are complete, most of the backend functionality of searching videos is in place. The only step left to have a working prototype is to take 11 advantage of the information returned from the database query by applying it visually to the Map Page. The design for this page is basically just a simple MKMapView from the Cocoa Touch library. This was the easiest of the three pages to design because the hard work of loading the Google Earth view and enabling moving and zooming through finger gestures is already done by the SDK. We simply choose a few settings, making sure to enable the blue blinking dot to show the user’s current position, and set the MapType to “Hybrid”, which is a mix of the road map and satellite views. Within just a few minutes, the view was set and ready for our Map Pin modifications. Next we had to add pins to the map based on the response data from the PHP on the WampServer. The iPhone SDK comes with a built in XML Parser, which we were able to easily use to extract the data from the XML string. The iPhone SDK provides an interface MKPinAnnotationView, but no default implementation of an MKAnnotation, so we were required to implement our own MapPin class in order to create and add pins to the MapView [1]. We create an MKAnnotation class, which gives us the ability to drop a pin at any given coordinate and display a default popup with a user defined title and subtitle [22]. However, for the MediaMap application, we need to customize the MKAnnotation to hold more information than those two fields. To do this, we override the MKAnnotationView class in order to change the methods which get called when a pin is created [23]. By changing the viewForAnnotation method, we add an icon image for the leftCalloutView and an arrow button for the right callout view. Figure 2.3 The leftCalloutView image, in this case a YouTube icon, we use to alert the user about the type of media each pin represents. The rightCalloutView button, seen as a blue right pointing arrow, can be clicked to show more information. In the case of video media, it will open the YouTube link for playback. 12 2.2.8 Video Playback Video playback on the iPhone is relatively simple. Because there is a built-in YouTube player, all we need to do is open the link, and the player will automatically be launched. There are several other ways to play the video, but this was the easiest and, in our case, most practical. The only issue with this method is that it must leave the application to launch the player so that when the video is over, the user needs to open the MediaMap application back up to continue. One other video palyback method that addresses this issue and generally creates a better experience for the user is to create a WebUIView which shows the thumbnail of the video. When the thumbnail is clicked, the default YouTube player is launched, only this time from within the WebUIView, which remains inside of the application [24]. Then when the video ends, it returns the user back directly to the MediaMap Map Page. The only problem with this method is that it required one more user click. We determined that there was not enough space within the MediaMap Map Page to insert a WebUIView without ruining the usability of the map itself. We investigated ways to hide the WebUIView and force a click without the user’s knowledge, but could not find a suitable method to achieve that goal. 13 CHAPTER 3 Completion 3.1 Sprint 3 With the playback of a video on the click of a Map Pin, our first prototype design is completed. Sprint 3 is reserved for testing and enhancement work; however, due to some of the setbacks early on in the project, we entered Sprint 3 already well behind schedule. In order to finish the prototype, the length of Sprint 2 was extended, and leaves only time for testing in Sprint 3. To test the application, we run several iterations through the entire program flow, from uploading a video, to searching for and viewing a video. We must make sure to use various combinations of input characters on the upload page and to upload from different locations to make sure the GPS is updating correctly. 3.2 Testing Results One problem we notice right away when we start to test our application was that no matter where the user or the pins are on the screen, the MapView always starts at the furthest zoom level, so that the entire globe is visible. Because all of our test pins are recorded in the Philadelphia area, it takes a lot of zooming for the user to see the difference between the multiple pins. We did find methods online to select an initial zoom area, but were unable to implement that before the submission of this project [25]. As far as user input goes, the name and description are URL Encoded before being sent to the PHP servers, so anything we tested successfully makes it through the network and into our database. The one field that matters is our side channel method for adding videos. If a bad value is entered, the insert works with no problem, but playback from the Map View fails, as expected, because of the bad URL. The location updates work perfectly fine as well, and is very accurate as long as the phone has service other than WiFi. With WiFi mode only, it still picks the correct general location, but is nowhere near as accurate as the GPS. To make sure other areas besides Philadelphia work properly, we input different coordinates manually into the database, including special cases such as POINT(0 0) and POINT(-180 90). We are pleasantly surprised with how quickly the entire system runs. We added a “Shake to reload” feature to the maps to allow a user to shake the iPhone and populate the screen with the latest database information. We found that after inserting information into the database, it shows up in the search query almost instantly, or at least as fast as we can switch to the Map Page and shake the iPhone. One bug that we have been unable to solve is a memory leak somewhere. As we mentioned earlier, Objective-C relies heavily on the C language and pointers without the use of an automatic garbage collector. Therefore, it is the programmer’s responsibility to find and remove any unused pointers and allocated memory. Somewhere our code does not handle 14 the memory allocation and release correctly, and the application will sometimes, particularly after several requests, run out of memory and crash. 3.3 Future Work The prototype version of MediaMap that we are submitting as the result of this Independent Study is far from a complete application. There are several missing features, most notably the inability to upload any media, the inclusion of videos only, and the lack of functionality on the Search Page. But in the short two month period of time, we created a working application from design to prototype that proves the possibility of a geospatially aware video database which can be viewed and queried by location on the iPhone Map View. With that said, there are some definite areas of expansion, besides the pieces which have already been listed as incomplete. As mentioned earlier, we created five database tables, but for the most part, only access two of them, media and location. The ultimate goal of this application is to act as an additional form of social networking information. A user will add and remove friends, and share videos and other media captured from their phone directly with other users. Our current setup has only one user, and it is the default for all media added to the database, but we left the database structure open to more users. The ability to create a MediaMap account which would store all of the user information and other websites’ account usernames and passwords opens up the possibility for a single sign on application which allows a user to update multiple different sites with more types of media than video from within the single application. One feature we missed from the Map View during testing was the ability to type in any address and have the globe immediately navigate to that location. In the current iteration, the user is presented with a globe and must manually navigate to anywhere they want to do. It would be a huge enhancement to incorporate more features into MediaMap, such as reverse geocoding, searching by address, and directions. Or, in a much later iteration, we would hope to integrate directly with the built-in Google Maps application which already has these features. Currently, it is not possible to modify the built-in maps or other standard iPhone applications at all, and that option may never be possible. The most valuable part of the application is its openness to modification and expansion. In a future iteration, the application could also interact with more sites than just YouTube or Flickr, for instance updating a user’s Facebook or Twitter account when a new media is posted. We could also allow for plaintext notes to be posted, which could take the form of a Facebook status update marked with a location of the user’s position. Some other types of media which we did not include at all in our initial prototype, but are available for capture on the iPhone include audio, drawings, weather and traffic updates, contact information, and calendar events. An ideal complete application would allow for the creation and sharing of any data found on the iPhone as a form of communication among both friends and strangers. The map could populate with information about the area, such as Wikipedia and News articles, as well as user submitted content. The inspiration would be to make MediaMap the ultimate resource for discovering any and all kinds of information about a particular location of interest. 15 CONCLUSION The goal of this research was to follow a structured agile software engineering process to design from the ground up a prototype application for the Apple iPhone to interact valuably with a geospatial video database. The goal of developing an iPhone application was to learn the Objective-C language and mobile development and networking. At the same time we learned how to design and schedule a project, while overcoming changes and obstacles to create a working product in a short amount of time. The MediaMap application serves as an example of the value of mobile applications, and is a first step towards a expansive and comprehensive location-aware social network hub. In designing this prototype, we learned the Objective-C and PHP languages, the MySQL geospatial database functions, and enhance our SQL and networking skills. We discovered and approached problems with agile solutions, and adapted our needs to fit the scheduled end date. The completed project is far from perfect, but accurately demonstrates the capabilities required for such an application exist currently. With more time and a better knowledge of the skill set, particularly of the Objective-C language and iPhone development, we believe it is completely possible to create a full working application based on our designs. With all of these things in mind, the immediate future goal is to continue development as currently designed to add the actual uploading of both video and images without the use of a side channel. After that, the next step would be to enhance the user account feature and implement the functionality behind the Search Options page. After that, MediaMap remains a work in progress, and leaves the door wide open for future creativity and expansion. 16 REFERENCES [1] I. Sommerville, Software Engineering, 8th ed., New York, New York: AddisonWesley, 2007. [2] Apple, Inc. “iPhone Dev Center”, Apple Developer Pages, 2010. [Online Software Download]. Available: http://developer.apple.com/iphone/index.action. [Accessed: May 12, 2010]. [3] J. Ray and S. Johnson, J. Ray and S. Johnson, Sams Teach Yourself: iPhone Application Development. Indianapolis, Indiana: Sams Publishing, 2010. [4] C. Dempsey, “Methods for Creating Spatial Databases,” GIS Lounge. Sept. 29, 2006. [Online]. Available: http://gislounge.com/methods-for-creating-spatial-databases/. [Accessed: May 21, 2010]. [5] Wikipedia, “Open Geospatial Consortium”, Wikipedia: The Free Encyclopedia. June 4, 2010. [Online]. Available: http://en.wikipedia.org/wiki/Open_Geospatial_Consortium. [Accessed July 19, 2010]. [6] R. Bourdon, Wamp Server 2.0i. GPL License, July 11, 2009. [Online Download]. Available: http://www.wampserver.com. [Accessed: May 23, 2010]. [7] Dyn Inc., “Dynamic DNS Free”, Dynamic DNS. Dynamic Hostname. 2010. [Online Software]. Available: http://www.dyndns.com. [Accessed: May 23, 2010]. [8] CollabNet. “Tortoise SVN,” Tigris.org. Subversion 1.6, May 2010. [Online Software Download]. Available: http://tortoisesvn.tigris.org/. [Accessed May 24, 2010]. [9] Geeknet, Inc. “SourceForge,” SourceForge.net. May 2010. [Online Software]. Available: https://sourceforge.net/. [Accessed May 24, 2010] Project Link: https://team5hangman.svn.sourceforge.net/svnroot/team5hangman/MediaMap/. [10] Oracle, “Introduction to MySQL Spatial Support,” MySQL Documentation. 11.16.1, 2010. [Online]. Available: http://dev.mysql.com/doc/refman/5.0/en/gisintroduction.html. [Accessed: June 16, 2010]. [11] Oracle, “Introduction to MySQL Spatial Support,” MySQL Documentation. 11.17.1 – 11.17.7, 2010. [Online]. Available: http://dev.mysql.com/doc/refman/5.1/en/spatialextensions.html. [Accessed: June 16, 2010]. [12] “Setting up Fields in your phpMyAdmin database tables,” PHP Tutorials, [Online]. Available: http://www.homeandlearn.co.uk/php/php12p3.html. [Accessed: May 24, 2010]. 17 [13] “How to transfer recorded video from iPhone 3GS,” iPhone Development Exchange, Sept. 13, 2010. [Online]. Available: http://www.iphonedevx.com/?p=192. [Accessed: June 18, 2010]. [14] Google, “Developer’s Guide: PHP,” YouTube APIS and Tools, Uploading Videos, 2010. [Online]. Available: http://code.google.com/apis/youtube/2.0/developers_guide_php.html#Uploading_Vid eos. [Accessed: July 3, 2010]. [15] Apple, Inc., “iOS Reference Library”, Apple Developer Pages. 2010. [Online]. Available: http://developer.apple.com/iphone/library/navigation/index.html. [Accessed: May 15, 2010]. [16] ohiyo1234, “Have problem with base64 Endcoder/decoder,” iPhone SDK Development Forum, Oct. 27, 2008. [Online]. Available: http://www.iphonedevsdk.com/forum/iphone-sdk-development/5752-have-problembase64-endcoder-decoder.html [Accessed: June 17, 2010]. [17] K. Yong, “YouTubeAPIS + iPhone = Cool mobile apps,” YouTube API Blog: News and Notes for Developers, Feb. 5, 2010. [Online]. Available: http://apiblog.youtube.com/2009/02/youtube-apis-iphone-cool-mobile-apps.html. [Accessed: July 2, 2010]. [18] Google, “GData Objective-C Client Library,” Google Code, Google Data APIS Objective-C Client Library, Release 1.10.0, Date of publication. [Online Download]. Available: http://code.google.com/p/gdata-objectivecclient/downloads/detail?name=gdata-objectivec-client-1.10.0.zip&can=2&q=. [Accessed: July 2, 2010]. [19] pdm, “Google’s GData Objective-C Client Library – iPhone SDK,” iPhone SDK Development Forum, Aug. 29, 2008. [Online]. Available: http://www.iphonedevsdk.com/forum/iphone-sdk-development/3148-googles-gdataobjective-c-client-library-iphone-sdk.html [Accessed: June 29, 2010]. [20] Digital Fish, Inc., “HTTPFileUploadSample,” CocoaDev, Dec. 3, 2008. [Online]. Available: http://www.cocoadev.com/index.pl?HTTPFileUploadSample [Accessed: June 15, 2010]. [21] W3Schools, “PHP Tutorial”, w3schools.com, 2010. [Online]. Available: http:// www.w3schools.com/php/default.asp [Accessed: June 25, 2010]. [22] Rupert, “iPhone Note #14: Drawing a Point, Line, Polygon on top of MKMapview,” iPhone And GIS Development Notes, Oct 2, 2009. [Online]. Available: http://www.gisnotes.com/wordpress/2009/10/iphone-devnote-14-drawing-a-pointline-polygon-on-top-of-mkmapview/. [Accessed: July 7, 2010]. 18 [23] J. Barros, “Getting Oriented with MapKit: Everything you need to get started with the new mapping framework,” slideshare, Nov. 2009. [Online]. Available: http://www.slideshare.net/360conferences/getting-oriented-with-mapkit-everythingyou-need-to-get-started-with-the-new-mapping-framework. [Accessed: July 12, 2010]. [24] Boydlee, “Auto playing a YouTube video inside WebUIView iPhone Objective-C SDK,” Lemonade Stand, Feb. 3, 2010. [Online]. Available: http://blog.lemonadestand.com.au/post/auto-playing-a-youtube-video-insidewebuiview-iphone-objective-c-sdk/23. [Accessed: July 14, 2010]. [25] Troy, “Set the Zoom Level of an MKMapView,” Backspace Prologue: Mistakes and learnings of an iPhone developer, Jan. 22, 2010. [Online]. Available: http://troybrant.net/blog/2010/01/set-the-zoom-level-of-an-mkmapview/. [Accessed: July 10, 2010]. [26] “Tutorial: Using phpMyAdmin to manage mySQL,” Vision Master Designs, July 25, 2008. [Online]. Available: http://visionmasterdesigns.com/tutorial-usingphpmyadmin-to-manage-mysql/. [Accessed: May 24, 2010]. [27] B. Wilson, “Google opens its APIS to iPhone SDK,” CNET, Mar. 20, 2008. [Online]. Available: http://reviews.cnet.com/8301-19512_7-10115433-233.html. [Accessed: June 29, 2010]. 19 APPENDIX A Sprint 0 Schedule 20 APPENDIX B Sprint 1 Schedule 21 APPENDIX C Sprint 2 Schedule 22 APPENDIX D Upload Use Case 23 APPENDIX E Search Use Case 24 APPENDIX F View Use Case 25 APPENDIX G Database Creation 26 APPENDIX H PHP Code SVN: https://team5hangman.svn.sourceforge.net/svnroot/team5hangman/MediaMap/PHP/ insert.php <?php $type = $_GET["type"]; $name = $_GET["name"]; $desc = $_GET["desc"]; $link = $_GET["link"]; $loc = $_GET["loc"]; date_default_timezone_set("America/New_York"); $date = date("Y-m-d"); $connect = mysql_connect('mccoey.selfip.net', <removed>, <removed>); if (!$connect) { die('Could not connect: ' . mysql_error()); } mysql_select_db('mediamap'); mysql_query("INSERT INTO mediamap.media (USER_ID, LINK, NAME, DATE, SIZE, DESCRIPTION, TYPE ) VALUES ('1', '" . $link . "', '".$name."', '".$date."', '0', '".$desc."', '".$type."');"); $mediaId = mysql_insert_id(); mysql_query("INSERT INTO mediamap.location ( MEDIA_ID, GEOTAG ) VALUES ('".$mediaId."', GeomFromText('".$loc."'));" ); printf("Insert Successful"); ?> 27 search.php <?php $type = $_GET["type"]; $BBOX = $_GET['BBOX']; date_default_timezone_set("America/New_York"); $date = date("Y-m-d"); $connect = mysql_connect('mccoey.selfip.net', <removed>, <removed>); if (!$connect) { die('Could not connect: ' . mysql_error()); } mysql_select_db('mediamap'); $result = mysql_query("SELECT NAME, LINK, DESCRIPTION, DATE, X(GEOTAG) AS 'X', Y(GEOTAG) AS 'Y' FROM mediamap.media JOIN mediamap.location ON mediamap.media.MEDIA_ID=mediamap.location.MEDIA_ID WHERE 1=MBRContains(GeomFromText('".$BBOX."'), GEOTAG)"); echo "<?xml version=\"1.0\" encoding=\"UTF-8\"?>"; echo "<entries>"; while($row = mysql_fetch_array($result)) { echo "<entry>"; echo "<name>".$row['NAME']."</name>"; echo "<type>".$type."</type>"; echo "<description>".$row['DESCRIPTION']."</description>"; echo "<date>".$row['DATE']."</date>"; echo "<link>".$row['LINK']."</link>"; echo "<geom>POINT(".$row['X']." ".$row['Y'].")</geom>"; echo "<lat>".$row['X']."</lat>"; echo "<lon>".$row['Y']."</lon>"; echo "</entry>"; } echo "</entries>"; ?> 28 APPENDIX I Objective-C Code SVN: https://team5hangman.svn.sourceforge.net/svnroot/team5hangman/MediaMap/Classes UploadView.m #import "UploadView.h" #import <CoreLocation/CoreLocation.h> @implementation UploadView @synthesize selectVideo; @synthesize videoCamera; @synthesize selectImage; @synthesize imageCamera; @synthesize upload; @synthesize fileName; @synthesize tempLink; @synthesize fileDescription; @synthesize thumbnailImage; @synthesize backgroundButton; @synthesize locMan; NSData *webData; CLLocation *currentLoc; #pragma mark GUI - (IBAction)keyboardClose:(id)sender { [fileName resignFirstResponder]; [fileDescription resignFirstResponder]; [tempLink resignFirstResponder]; } #pragma mark Video - (void)pickVideo:(UIImagePickerControllerSourceType)sourceType { UIImagePickerController *picker = [[UIImagePickerController alloc] init]; picker.delegate = self; picker.allowsEditing = NO; picker.sourceType = sourceType; picker.mediaTypes = [NSArray arrayWithObject:(NSString *)kUTTypeMovie]; [self presentModalViewController:picker animated:YES]; [picker release]; } - (IBAction)selectVideoPressed:(id)sender { [self pickVideo:UIImagePickerControllerSourceTypeSavedPhotosAlbum]; } - (IBAction)videoCameraPressed:(id)sender { [self pickVideo:UIImagePickerControllerSourceTypeCamera]; } #pragma mark Image - (void)pickImage:(UIImagePickerControllerSourceType)sourceType { UIImagePickerController *picker = [[UIImagePickerController alloc] init]; picker.delegate = self; picker.sourceType = sourceType; [self presentModalViewController:picker animated:YES]; [picker release]; } 29 - (IBAction)selectImagePressed:(id)sender { [self pickImage:UIImagePickerControllerSourceTypeSavedPhotosAlbum]; } - (IBAction)imageCameraPressed:(id)sender { [self pickImage:UIImagePickerControllerSourceTypeCamera]; } #pragma mark ImagePicker - (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info { //Check if video or image NSString *mediaType = [info objectForKey:UIImagePickerControllerMediaType]; if ([mediaType isEqualToString:@"public.movie"]) { NSLog(@"Found a movie."); thumbnailImage.image = [UIImage imageNamed:@"movie.png"]; //videoInfo = info; } else if ([mediaType isEqualToString:@"public.image"]) { NSLog(@"Found an image."); UIImage *origImage = [info objectForKey:UIImagePickerControllerOriginalImage]; thumbnailImage.image = origImage; webData = UIImagePNGRepresentation(origImage); [origImage release]; } [picker dismissModalViewControllerAnimated:YES]; } - (void)imagePickerControllerDidCancel:(UIImagePickerController *)picker { [picker dismissModalViewControllerAnimated:YES]; } #pragma mark Upload -(void)uploadPressed:(id)sender { //Get current Location as WKT String NSString *wktStr = [self getLocation]; //Get Title and Description NSString *titleStr = fileName.text; NSString *descStr = fileDescription.text; NSString *temp = tempLink.text; NSString *urlStr; if([titleStr isEqualToString:@""]) { NSLog(@"NULL Title"); titleStr = [[NSString alloc] initWithString:@"No Title"]; } if([descStr isEqualToString:@""]) { NSLog(@"NULL desc"); descStr = [[NSString alloc] initWithString:@"No Description" ]; } 30 //if ([temp isEqualToString:@""]) { if(temp == NULL) { //Upload Video link to to database //At this time, all videos are ?v=NmxOjfqlb0o urlStr = [[NSString alloc] initWithFormat:@"http://mccoey.selfip.net:8080/insert.php? type=VIDEO&name=%@&desc=%@&loc=%@&link=NmxOjfqlb0o", titleStr, descStr, wktStr]; } else { //Upload Video link to to database urlStr = [[NSString alloc] initWithFormat:@"http://mccoey.selfip.net:8080/insert.php? type=VIDEO&name=%@&desc=%@&loc=%@&link=%@", titleStr, descStr, wktStr, temp]; } NSLog(@"URL: %@", urlStr); NSURL *url = [[NSURL alloc] initWithString: [urlStr stringByAddingPercentEscapesUsingEncoding:NSASCIIStringEncoding]]; NSLog(@"%@", [url absoluteString]); NSURLRequest *request = [[NSURLRequest alloc] initWithURL: url]; NSHTTPURLResponse *response; NSError *error; [NSURLConnection sendSynchronousRequest:request returningResponse:&response error: &error]; NSLog(@"Status Code: %d", [response statusCode]); NSLog(@"Status: %d", [response observationInfo]); //Clear all fileName.text = @""; fileDescription.text = @""; tempLink.text = @""; thumbnailImage.image = NULL; NSLog(@"Done uploading"); } /* getLocation returns the current location * as a wktString singular POINT */ - (NSString *) getLocation { NSLog(@"getLocation"); NSLog(@"POINT(%f %f)", currentLoc.coordinate.latitude, currentLoc.coordinate.longitude); return [[NSString alloc] initWithFormat:@"POINT(%f %f)", currentLoc.coordinate.latitude, currentLoc.coordinate.longitude]; } // Implement viewDidLoad to do additional setup after loading the view, typically from a nib. - (void)viewDidLoad { [super viewDidLoad]; locMan = [[CLLocationManager alloc] init]; locMan.delegate = self; locMan.desiredAccuracy = kCLLocationAccuracyBest; [locMan startUpdatingLocation]; } #pragma mark Location 31 - (void)locationManager:(CLLocationManager *)manager didFailWithError:(NSError *)error { if(error.code == kCLErrorDenied) { [manager stopUpdatingLocation]; [locMan release]; locMan = nil; } } - (void)locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation *)newLocation fromLocation:(CLLocation *)oldLocation { NSLog(@"Updating location (%f, %f)", newLocation.coordinate.latitude, newLocation.coordinate.longitude); currentLoc = [[CLLocation alloc] initWithLatitude:newLocation.coordinate.latitude longitude:newLocation.coordinate.longitude]; } #pragma mark - (void)didReceiveMemoryWarning { // Releases the view if it doesn't have a superview. [super didReceiveMemoryWarning]; } - (void)viewDidUnload { [super viewDidUnload]; } - (void)dealloc { [selectVideo release]; [videoCamera release]; [selectImage release]; [imageCamera release]; [upload release]; [fileName release]; [tempLink release]; [fileDescription release]; [thumbnailImage release]; [backgroundButton release]; [webData release]; [devKey release]; [locMan release]; [super dealloc]; } @end MapView.m #import "MapView.h" #import "MapPin.h" #import <MapKit/MapKit.h>; @implementation MapView; @synthesize map; @synthesize webView; NSMutableString *mediaName; NSMutableString *description; NSMutableString *link; 32 BOOL onName; BOOL onDesc; BOOL onLink; BOOL onLat; BOOL onLon; double lat; double lon; MapPin *pin; // Implement viewDidLoad to do additional setup after loading the view, typically from a nib. - (void)viewDidLoad { [super viewDidLoad]; map.delegate = self; [self searchForMedia]; } - (void)viewDidAppear: (BOOL)animated { [self becomeFirstResponder]; [super viewDidAppear:animated]; } -(void)searchForMedia { NSString *urlStr = [[NSString alloc] initWithFormat:@"http://mccoey.selfip.net:8080/search.php? type=VIDEO&BBOX=%@", @"POLYGON((-180 90,180 90,180 -90,-180 -90,-180 90))"]; NSURL *url = [[NSURL alloc] initWithString: [urlStr stringByAddingPercentEscapesUsingEncoding: NSASCIIStringEncoding]]; NSLog(@"%@", [url absoluteString]); NSURLRequest *request = [[NSURLRequest alloc] initWithURL: url]; NSHTTPURLResponse *response; NSError *error; //Get XML reply in String format and then change to NSData for NSXMLParser NSData *reply = [NSURLConnection sendSynchronousRequest:request returningResponse:&response error: &error]; NSString *stringReply = (NSString *)[[NSString alloc] initWithData:reply encoding:NSUTF8StringEncoding]; NSData *xmlData = [stringReply dataUsingEncoding: NSUTF8StringEncoding]; NSLog(@"XML: %@", stringReply); //Parse and Add points NSXMLParser *xmlParser = [[NSXMLParser alloc] initWithData:xmlData]; [xmlParser setDelegate:self]; [xmlParser parse]; } -(void)updateBounds { /* this code borrowed from deadroxy at: * http://stackoverflow.com/questions/2081753/getting-the* bounds-of-an-mkmapview */ //To calculate the search bounds... //First we need to calculate the corners of the map so we get the points CGPoint nePoint = CGPointMake(map.bounds.origin.x + map.bounds.size.width, map.bounds.origin.y); CGPoint swPoint = CGPointMake((map.bounds.origin.x), (map.bounds.origin.y + map.bounds.size.height)); 33 //Then transform those point into lat,lng values CLLocationCoordinate2D neCoord; neCoord = [map convertPoint:nePoint toCoordinateFromView:map]; CLLocationCoordinate2D swCoord; swCoord = [map convertPoint:swPoint toCoordinateFromView:map]; /* End Borrowed Code */ NSLog(@"NE: %f",neCoord); NSLog(@"SW: %f",swCoord); [NSThread sleepForTimeInterval:5.0]; [self updateBounds]; } - (void)didReceiveMemoryWarning { // Releases the view if it doesn't have a superview. [super didReceiveMemoryWarning]; // Release any cached data, images, etc that aren't in use. } - (void)viewDidUnload { [super viewDidUnload]; // Release any retained subviews of the main view. // e.g. self.myOutlet = nil; } - (void)dealloc { [super dealloc]; [mediaName release]; [description release]; [link release]; } #pragma mark parser - (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName attributes:(NSDictionary *)attributeDict { if ([elementName isEqualToString:@"name"]) { onName = YES; } if ([elementName isEqualToString:@"description"]) { onDesc = YES; } if ([elementName isEqualToString:@"link"]) { onLink = YES; } if ([elementName isEqualToString:@"lat"]) { onLat = YES; } if ([elementName isEqualToString:@"lon"]) { onLon = YES; } } - (void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string { // only log the text of a node if it's a "screen_name" node if( onName ) { mediaName = [[NSMutableString alloc] initWithString:string]; 34 NSLog(@"String: %@", mediaName); } if( onDesc ) { description = [[NSMutableString alloc] initWithString:string]; NSLog(@"String: %@", description); } if( onLink ) { link = [[NSMutableString alloc] initWithString: string]; NSLog(@"String: %@", mediaName); } if( onLat ) { lat = [string doubleValue]; } if( onLon ) { lon = [string doubleValue]; } } - (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName { if ([elementName isEqualToString:@"entry"]) { //Create Pin CLLocationCoordinate2D coordinate; coordinate.latitude = lat; coordinate.longitude = lon; pin = [[MapPin alloc] initWithCoordinates:coordinate placeName:mediaName description:description link:link]; [map addAnnotation:pin]; } if ([elementName isEqualToString:@"name"]) { onName = NO; } if ([elementName isEqualToString:@"description"]) { onDesc = NO; } if ([elementName isEqualToString:@"link"]) { onLink = NO; } if ([elementName isEqualToString:@"lat"]) { onLat = NO; } if ([elementName isEqualToString:@"lon"]) { onLon = NO; } } #pragma mark mapView -(MKPinAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id <MKAnnotation>)annotation { if(map.userLocation == annotation){ return nil; } MKPinAnnotationView *annView = (MKPinAnnotationView *) [self.map dequeueReusableAnnotationViewWithIdentifier:@"id"]; if(annView == nil){ annView = [[[MKPinAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier: @"id"] autorelease]; annView.canShowCallout = YES; annView.rightCalloutAccessoryView = [UIButton buttonWithType:UIButtonTypeDetailDisclosure]; 35 annView.leftCalloutAccessoryView = [[[UIImageView alloc] initWithImage:[UIImage imageNamed:@"youtube.png"]] autorelease]; } return annView; } -(void)mapView:(MKMapView *)mapView annotationView:(MKAnnotationView *)view calloutAccessoryControlTapped:(UIControl *)control { MapPin *tempPin = [view annotation]; NSString *fullLink= [[NSString alloc] initWithFormat: @"http://www.youtube.com/watch?v=%@", [tempPin link]]; NSLog(@"View Tapped: %@", fullLink); [[UIApplication sharedApplication] openURL:[NSURL URLWithString:fullLink]]; [fullLink release]; [tempPin release]; } //refresh on shake -(void)motionEnded:(UIEventSubtype)motion withEvent:(UIEvent *)event { if(event.type == UIEventSubtypeMotionShake) { NSLog(@"SHAKE"); [self searchForMedia]; } } -(BOOL) canBecomeFirstResponder { return YES; } #pragma mark Video @end 36