füd5, a restaurant suggestion android application

59
A RESTAURANT SUGGESTION ANDROID APPLICATION BY TEAM 5 JAGATDEEP ANAND ALEX BROWN ERIC BLACK IVAN GONZALEZ DAVID KARAPETIAN NICU LISTANA ANTHONY WONG SAN FRANCISCO STATE UNIVERSITY CSC 413: SOFTWARE DEVELOPMENT SUMMER 2015

Upload: nicu-listana

Post on 23-Jul-2016

220 views

Category:

Documents


0 download

DESCRIPTION

CSC 413 - Software Development Student Project Documentation San Francisco State University Summer 2015 Credits: Jagatdeep Anand, Alex Brown, Eric Black, Ivan Gonzalez, David Karapetian, Nicu Listana, and Anthony Wong Full source code available here: https://github.com/awong9/t5 Project's presentation slides are available here: http://www.slideshare.net/apebeast/fd5-a-restaurant-suggestion-android-application For more information and distribution permissions, please e-mail Mark Sosnick at: [email protected]

TRANSCRIPT

Page 1: Füd5, A restaurant suggestion android application

A RESTAURANT SUGGESTION

ANDROID APPLICATION

BY TEAM 5

JAGATDEEP ANAND

ALEX BROWN

ERIC BLACK

IVAN GONZALEZ

DAVID KARAPETIAN

NICU LISTANA

ANTHONY WONG

SAN FRANCISCO STATE UNIVERSITY – CSC 413: SOFTWARE DEVELOPMENT – SUMMER 2015

Page 2: Füd5, A restaurant suggestion android application

2

Table of Contents

Section 1: Overview & Process ...................................................................................... 3

Executive Summary ........................................................................................................ 4

Specifications .................................................................................................................. 5

Initial concept .................................................................................................................. 7

Final project flow ............................................................................................................. 9

Weekly Meeting ............................................................................................................ 10

Collaborative Tools ....................................................................................................... 13

Section 2: Front End (User Interface) .......................................................................... 15

Splash Screen Activity .................................................................................................. 16

Main Activity (Search Page) ......................................................................................... 18

Result Page Activity ...................................................................................................... 20

Settings Activity ............................................................................................................. 23

Dev Playground ............................................................................................................ 24

Section 3: Back End ....................................................................................................... 25

Third-Party APIs ............................................................................................................ 26

RestaurantApiWrapper library ...................................................................................... 28

Restaurant Selection Algorithm .................................................................................... 41

Data Storage ................................................................................................................. 44

Utilities ........................................................................................................................... 46

Section 4: Conclusion & Future Goals ........................................................................ 47

Future stretch goals ...................................................................................................... 48

Monetization .................................................................................................................. 50

What We Would Do Differently Next Time ................................................................... 51

Bibliography/Resources ................................................................................................ 52

Section 5: Presentation Slides ..................................................................................... 53

Page 3: Füd5, A restaurant suggestion android application

SECTION 1: OVERVIEW & PROCESS

Page 4: Füd5, A restaurant suggestion android application

4

Executive Summary

Füd5 is an Android application that helps users find nearby restaurants. The

application has a simple interface that allows users to get a nearby restaurant

recommendation by pressing the "Füd Plz" button. The application displays the name of

the restaurant and an image provided by Yelp, and a Google map showing where the

restaurant is. The user can then accept or reject the recommendation. If the user

accepts the recommendation, the application provides directions to the restaurant. If the

user rejects the recommendation, the application will recommend another restaurant.

There are two types of rejections: "maybe later..." and "always ignore." The "maybe

later" button will hide the restaurant during this current search, and will display it in

future searches after a certain time period. The "always ignore" button will put the

restaurant in a rejection list which will prevent it from ever being a result in future

searches. The application remembers the choices made and will adjust its future

recommendations based on those choices. The app was designed to have an easy to

use interface which allows a user to go from start to finish using only their thumb.

The application was developed over the course of ten weeks by a team of seven

students. Each week the team met on Wednesday to discuss the project. In the

beginning the meetings were mostly brainstorming sessions to decide how the

application should look and feel. One of our use cases was “You are a hungry tourist in

a foreign country.” This meant designing an easy to use application that would display

results with a single tap. As the application took form towards the end, everyone

focused on technical issues such as how the result algorithm should be implemented or

fixing bugs. This made scrums very useful to avoid duplicate work or code conflicts as

everyone worked off the same codebase.

In the end, we believe we have produced an application that is intuitive and easy

to use, and in the process of development learned a great deal about Android

programming as well as collaborative tools and teamwork methodology for software

development.

Page 5: Füd5, A restaurant suggestion android application

5

Specifications

Our original specs are shown below. Items 1 through 6 and 14 through 22 were

set by Professor Sosnick. The rest were set by the team. Professor Sosnick’s notes are

visible on the spec sheet.

Figure 1 - Pre-development specification sheet with annotations by Prof. Sosnick

To fulfill item 6, we chose the following special features:

1. the ability to pull up restaurant menus with the OpenMenu API, and

2. the algorithm we would use to sort our recommended restaurants.

Unfortunately, OpenMenu did not grant our group a key to use their API. Luckily, we

were able to use the Locu API instead. This provided the added benefit of allowing us to

access and display a restaurant’s open hours.

Page 6: Füd5, A restaurant suggestion android application

6

Our final specifications evolved into the following:

Figure 2 – Specifications reflected in the final build

Item 9 was amended when during Milestone 1 when it became clear the UI allowed the

main functionality to be controlled on the bottom of the screen -- reachable with the

thumb.

Page 7: Füd5, A restaurant suggestion android application

7

Initial concept

Figure 3 and Figure 4 show early sketches made by the members of the team

before we collaborated on wireframe design and discussed special features. They show

the entire application lifecycle. Nicu and Eric both independently developed the idea

keeping track of the user’s opinion of different restaurants, and it was agreed that this

idea should be implemented. This was further refined into the Restaurant Selection

Algorithm (pg. 41) which could provide a ranked list of results based on the user’s

opinion of previously visited restaurants. This, in turn, informed the idea that, after the

user searches for restaurants, we should show only one result at a time.

Figure 3 - Pre-development sketch of application flow by Nicu

Page 8: Füd5, A restaurant suggestion android application

8

Figure 4 – Pre-development sketch of application flow by Eric

Compare these early sketches with Figure 5 on the next page; the end result

ended up aligning closely with our early concept. We felt that even if extra features were

incorporated into the application, we should make sure the base functionality of the

application is as simple to use as possible, without adding needless extra activities. In

the end, the application’s main functionality is contained within only two activities: The

Search Page and the Result Page.

Page 9: Füd5, A restaurant suggestion android application

9

Final project flow

Figure 5 – Diagram of final project flow

Page 10: Füd5, A restaurant suggestion android application

10

Weekly Meeting

This section lists the dates by which certain tasks were scheduled to be

completed, and what date they were actually completed. This portion also contains the

breakdown of the team's weekly scrum meetings, the feedback we received from

milestones we achieved, and the changes that we made:

6/17/15

Tasks completed

● We created our first “hello world” application on Android Studio.

● Researched Google and Yelp locations APIs.

TODO

● Familiarize ourselves with Github so that later on in the semester, things would

go smoothly.

6/24/15

Tasks completed

Researched SQLite,Yelp API and Location services

● Formalized each member’s role.

TODO

● Begin working on Google Maps API.

● Begin working on Location API and access/sort data.

● Focus on Wire frame design.

● Begin working on EULA (about page).

7/1/15

Tasks completed

● Tested sql for front end

● Completed Yelp API wrapper, uploaded test code to find user location.

● tested Yelp wrapper.

● Worked on Splash screen.

● Obtained Yelp key, searched for health inspection API.

● Began building class and interface for Google Maps API.

Page 11: Füd5, A restaurant suggestion android application

11

TODO

Begin implementing selector class which depends on database

● Try to get an activity to work with Google Maps API.

● Implement Splash Screen.

7/15/15

Tasks completed

Displaying Maps on result page activity.

● format the layout in order to display the map properly.

● Adjusted the splash screen to properly handle location services

● Displayed the End-User License Agreement.

● Merged Restaurant Test into GUI.

● Created a working "Red List".

● Added results page.

TODO

● Implement images of restaurants on results page.

● Applying food preference setting.

7/22/15

Tasks completed

● We designed the result page and the menu bar icons.

● There was some debugging for the GUI plus provided functionality to some

buttons.

● Added buttons to the result page of the application.

● We were able to load images in the main activity.

● Completed the End-User License Agreement component.

● Added markers to google maps and got the maps to function properly.

TODO

● Modify GUI to make it more user-friendly

● Integrate Locu Menu Dialog with the main activity.

● Preload the restaurant images and the rating images as well.

● Complete “About Application” portion

● Obtain Google Maps API attribution and display information

● Put finishing touches on selector and work on Google Maps.

Page 12: Füd5, A restaurant suggestion android application

12

7/29/15

Tasks completed

● Began working on the GUI portion of the application and “Let’s Go” button.

● Began to implement the results page

● Created Dialogues (Menu etc...)

● Optimization of front end and back end.

● Started working on the selector class.

● Got the image to pre-load

● Began working on documentation and fixing bugs.

● Implemented Google Maps API attribution

TODO

● Finish implementing the Google Maps API attribution.

● Debug and begin working on Documentation.

● Polish graphics icon

● Integration of Uber (a method of transporting user to restaurant)

● Attempt to integrate a Health Inspection API (short description)

● Maybe integrate some sort of animation.

Page 13: Füd5, A restaurant suggestion android application

13

Collaborative Tools

Slack

Slack1 was our primary mode of communication beyond direct communication

before and after class and the weekly meetings. We chose it over e-mail, text

messaging, or other means of communication because it offers group messaging that it

1) is direct and organized, 2) cross-platform compatible, and 3) allows integration with

the other services used during development. Essentially, Slack provides the immediacy

of text messaging if the Slack application is installed on each team members’ phones,

but can be selectively silenced. Initially, we posted group messages under the default

#general channel. As time progressed and we needed to focus conversations around

particular topics, we created channels specifically for front-end and back-end

development, resources, bugs and other issues, and documentation. If anyone in the

group needed to get in touch with multiple team members, direct messages or private

groups were available. We found creating a #commits channel to be particularly helpful,

as team members could coordinate when to push changes without creating

unnecessary merges or conflicts.

Google Drive

We used Google Drive to host and share content, including project specifications,

wireframe images, etc. In addition, we used shared documents to track the project

backlog and collaborate on this document and the final in-class presentation. We find

Google Drive to be a great tool for quick collaboration.

Microsoft Word

This document was finalized using a group-editable Microsoft Word document

hosted on OneDrive. A link was shared on Slack with the whole team so any team

member could make quick edits in Word Online, or more robust formatting edits on a

full-featured local copy of Word.

1 Slack: https://slack.com/

Page 14: Füd5, A restaurant suggestion android application

14

Git & GitHub

While we were required to use Git/GitHub for this project, we believe that we

utilized GitHub to its full potential. Though Git has a bit of a learning curve, by the end of

the semester we had become proficient with committing and pushing changes from

local to remote branches, adding and deleting new branches, and merging branches

together. In the first 6 weeks we opted to work individually in separate branches and

merge our progress into a production branch that contained only working code. As a

milestone was reached, we merged the production branch into the master branch. While

this created some issues in terms of merging cleanly, our experience with multiple

branches informed our final work on the project. During the last 4 weeks we worked off

a single branch, adjusting the root gitignore file so Android Studio local settings in the

.idea folder were not needlessly updated. In one of our weekly meetings, we discussed

best practices for using Android Studio with GitHub. While learning the command line

was helpful in becoming familiar with practices and terminology, and is undoubtedly

important for other projects where the development environment may not have such

tight GitHub integration, we find that it is definitely possible for 7 people to collaborate

on a single remote branch of a repository hosted on GitHub within Android Studio

without ever using the Git command line.

As for GitHub, we found several added features to be quite useful. For example,

the Wiki was helpful in that we were able to link to various resources, including our

whiteboard sketches, program specs, a task backlog, and API terms of service and

attribution requirements. In addition, we wrote extensive notes on various aspects of the

project, including the various activities, APIs, and libraries used. In addition to being

useful as a resource for everyone during the development process, these notes were

helpful as a starting point for this document.

Another useful feature was the issue tracker. Its helpfulness was not so apparent

until the later stages of development when the application was almost-fully

implemented. At that point, a new issue could be opened for a bug, wherein a team

member would describe the scope of the bug and how it could be duplicated. In turn, a

team member with the necessary time and knowledge to resolve the issue would

provide a fix. By including the issue number in the commit message (e.g. “issue #3”) the

commit could be marked as fixed. Finally, after verifying that the issue was fixed, the

issue could be closed.

Page 15: Füd5, A restaurant suggestion android application

SECTION 2: FRONT END (USER INTERFACE)

Page 16: Füd5, A restaurant suggestion android application

16

Splash Screen Activity

Sketches and Screenshots

Description

The splash screen is an activity which displays when the application is loading

from the first time or from an inactive state. It displays the application’s logo and allows

us to take care of several “housekeeping” tasks before launching the Main Activity.

First, the activity displays the logo for 3 seconds. The screen is empty other than

the FuD5 logo and acts as the entry point for the application if it was not already running

or its state was cleared from memory by the Android OS due to inactivity. During the

wait time, any restaurants in the database yellow list with an addition timestamp longer

Figure 7 - Screenshot of final version's Splash

Screen on Nexus 7

Figure 6 - Pre-development wireframe sketches of

Splash Screen and Result Page

Page 17: Füd5, A restaurant suggestion android application

17

than 1 week are deleted. (See Restaurant Selection Algorithm for a description of the

green, yellow, and red lists.)

After the 3 second pause, the activity checks whether the user has agreed to the

End-User License Agreement. If this is the first time the user has run the program, the

answer will be no, and the End-User License Agreement dialog is displayed. The dialog

cannot be cancelled and the user must press "I agree" to proceed. If this is not the first

time the user has run the application and they previously agreed to the terms of service,

the End-User License Agreement dialog is not displayed.

Finally, the activity checks whether location services have been enabled; they

are considered enabled if either GPS or network location services are active. If neither

are not enabled, the activity opens the "Use Google Location services?" dialog. If user

presses "Yes plz" they are directed to Android Location Settings; after user turns on

location services, if they press the "Back" button or otherwise return to the application,

they are taken to the main activity. If the user presses "Maybe later" they are taken to

the main activity.

Figure 9 – End User License Agreement dialog displayed on HTC One M7 (5”)

Figure 8 – Application asks user if he/she wishes to turn on Location Services. Displayed on HTC One M7 (5”).

Page 18: Füd5, A restaurant suggestion android application

18

Main Activity (Search Page)

Sketches and Screenshots

Description

The MainActivity was conceived with the idea that the user can simply press the

“Fuz Plz” button to find a great nearby restaurant to try today. As such, the button is

conveniently placed at the bottom of the screen within easy reach of the thumb. By

default, if Android Location Services is on, the application will determine the device’s

current location and use that as the center point of the search.

Figure 10 - Pre-development wireframe

sketch of Main Activity

Figure 11 - Screenshot of Main Activity at Milestone 1, with

annotations by Prof. Sosnick

Page 19: Füd5, A restaurant suggestion android application

19

The device’s location,

approximated as an address, is

shown as one of the fields at the top

of the activity. By filling out or

changing these fields, the user can

answer the question, “What would you

like to eat?” These fields are:

Choose Different Location:

By pressing the edit text field, the user

can type their own city or address to

use as a central point. Or, the user

can press the crosshair button to

again retrieve the device’s current

location (say, if they have moved

since loading the activity).

Search Terms: While optional,

entering in additional search terms will

help refine the results. For example,

one could enter “vegetarian” to restrict

the results to restaurants featuring

vegetarian cuisine.

Max Radius: A default

maximum radius of 0.5 miles was

chosen because the results would

consist of restaurants within easy

walking distance. Pressing on the

distance text allows the user to

choose a radius of up to 10 miles from

a pulldown menu.

Minimum Rating: Selecting a

rating from 0 to 5 stars in half-star increments allows the user to filter out results which

fall below the minimum rating. By default, this is set at 3½ stars.

Figure 12 - Screenshot of final version's Main Activity

on an HTC One M7 (5”)

Page 20: Füd5, A restaurant suggestion android application

20

Result Page Activity

Sketches and Screenshots

Early on in the application’s

development process, we

considered showing a handful of

restaurants and their relevant info

on the Result screen pages, as

shown in the pre-development

sketch. However, we eventually

decided on displaying one

restaurant at a time, in keeping

with the idea that after our

restaurant selection algorithm was

applied to a list of potential

Figure 14 - Pre-development wireframe sketch of

the Result Page Activity

Figure 13 - Screenshot of Result

Page at Milestone 1

Figure 15- Single-result Result Page concept

Page 21: Füd5, A restaurant suggestion android application

21

restaurants, the first result would be a good potential match. While implementing this

design, it became quickly apparent how limited space was on the screen. If we

constructed a UI exactly like the one in this mockup, screen real estate would have

been limited. We would not be able to present information about restaurants in a robust

way so as to make them seem instantly appealing.

Additionally, Anthony suggested we could save some space if we overlap the

restaurant name and star rating over the image, and to zoom the image so it wouldn’t

change size when the aspect ratio changed. Although the “Don’t Show” button is shown

in the picture above to be changed to “No Way!” we opted for another of Prof. Sosnick’s

suggestions, “Always Ignore.”

Description

After ResultPageActivity has an

ordered list of restaurants, it takes the

first one off the list and sets up a

Google Map with a pin at that

restaurant’s location, along with the

restaurant’s Yelp star rating. Then, it

displays the restaurant’s name. If the

name is too long to display fully, the font

is made smaller. If the restaurant has an

associated image, it will be loaded and

displayed.

If the next restaurant on the list

has an image, it will be also be

preloaded into memory. This means

that if the user rejects the first

restaurant, ResultActivity doesn’t have

wait to load that image; it can just grab it

from memory.

Figure 16 - Screenshot of final version's Result Page on

HTC One M7 (5”)

Page 22: Füd5, A restaurant suggestion android application

22

Dialogs

The Result Page Activity title bar contains two

buttons which open dialogs: one to display restaurant

menus and one to display more information about the

restaurant. The restaurant menus information and

open hours are obtained from Locu, if a venue which

corresponds to the current restaurant is found and

Locu provides that information. In the case of the

restaurant menus button, if menus are unavailable,

an alert dialog informing the user that menus were

not found is shown in lieu of menu data. In the case

of the more info dialog, the open hours of the

restaurant obtained from Locu is shown in addition to

additional information such as categories and

restaurant phone number obtained from Yelp.

For the purpose of optimization, we opted not

to perform Locu API queries as a batch process for

every single restaurant in the list of restaurants

returned by Yelp. This would necessitate up to 40

separate calls: one to

find a potential Locu

venue match for a

given restaurant and

another to load detailed data such as complete menus

for the matching venue, for each of up to 20 restaurants

returned by the Yelp API query. Rather, we perform on

demand the two queries necessary to find and evaluate

a match, which happens when one of the two title bar

buttons is pressed for the first time for an individual

restaurant. We prevent a duplicate query from being

made, thus saving API calls. The main drawback to this

technique in terms of user experience is that there may

be a delay of a few seconds in the case a large

restaurant menu must be parsed and written to an object

prior to rendering the dialog. If the query had been

performed in advance, there would not be a significant

delay. Even so, we found the tradeoff to be worthwhile,

as Locu only provides a limited number of free-of-charge

API calls per day—1,000, as of this writing, which could

easily be expended with as little as 25 searches.

Figure 17 – More Info dialog on HTC

One M7 (5”)

Figure 18 – Restaurant Menu dialog

on HTC One M7 (5”)

Page 23: Füd5, A restaurant suggestion android application

23

Settings Activity

The Settings Activity allows the user to configure and access information about the

application. Figure 20 describes the function of each settings component.

Figure 19 - Screenshot of final version's Settings Page on HTC One M7 (5”)

Settings Activity Components

Component Purpose

About this app Lists application name, version, authors, and relevant copyright and licenses.

End User License

Agreement

Explains the terms of use. This dialog is identical to the one displayed to the user the first time the application launches.

Clearing history

Allows the user to view and remove ignored restaurants, clear user settings, and clear either the ignored restaurant history (red list) or all restaurant history (green, yellow, and red lists).

Pressing the icon opens a tooltip that explains the purpose of each Clear History checkbox item so the user understands what data is being cleared.

Manage services

Takes user to Android Location Settings to turn location services on or off.

Figure 20 - Components

Page 24: Füd5, A restaurant suggestion android application

24

Dev Playground

The Dev Playground, included below the settings, contains several test activities

and featured which we opted not to include in the final version of the application. This

portion of the Settings Page will be removed in the event that the application is released

to the public.

The components of the Dev Playground were useful in demonstrating

functionality of backend code and to debug the application by compartmentalizing

certain features/ Much of the work on the Locu menu test activity transferred over to the

menu button on the results page, and the database test activity aided in fixing bugs

where the wrong result was added to user preferences, or was not added at all.

In addition, several features which were considered for the final application were

omitted, namely the “Let’s Go” Follow-up Interval and the Default Settings activity.

Dev Playground Components

Component Purpose

Restaurant Selector Demo Allowed us to test our Restaurant Selection Algorithm by showing, step by step, how a list of restaurants obtained from Yelp is refined to prioritize the displayed results.

Database Test Allowed us to display the contents of the green, yellow, and red lists as well as add and remove test entries.

Image Test Performs a Yelp API query and displays the dimensions of the images provided for each restaurant. This allowed us to determine that we needed to resize/crop images for display.

Locu Test Displays menus for 4 preset restaurants or allows the user to pull up a restaurant menu by Locu ID. A Locu API query is performed to obtain the menu information.

Google Map Test Simply displays a pin on a map.

Display Shared Preferences Displays the contents of UserSettings.xml, which are the Android Shared Preferences variables used throughout the application.

Figure 21 – Dev Playground Components

Page 25: Füd5, A restaurant suggestion android application

SECTION 3: BACK END

Page 26: Füd5, A restaurant suggestion android application

26

Third-Party APIs

This section details our use of third-party application programming interfaces

(APIs) to obtain information to display to the user based on his/her preferences. The

implementations of both Yelp and Locu API queries are contained within the library

RestaurantApiWrapper, which is described in detail in the following section.

Yelp

Yelp is a consumer-facing web-based service that allows users to find

information about business venues and write reviews. Businesses can register with Yelp

to update their listing(s) and respond to consumer reviews. We perform a Yelp API

query to obtain information about restaurants filtered by the user’s choice of location

(either the device’s current location or custom input), a maximum search radius, a

minimum Yelp-star rating, and optional search terms. Information displayed to the user

consists of the restaurant name, address, distance from search location, Yelp

categories, and business phone number. Internally, we use Yelp’s unique per-venue ID

strings to record the user’s history of liked and disliked restaurants in the database, and

use the provided latitude and longitude to display restaurant results on a Google Map

and provide directions. In addition, we use the URL provided by Yelp to download and

display an image for each restaurant displayed.

Locu

While Yelp’s website provides users with open hours and menus for many

restaurants, this information is not available through the Yelp API, so we opted to

supplement our information by using the Locu API. Locu is a developer and business-

owner facing web-based service that allows application and website developers to

obtain information about businesses worldwide, or facilitate business owners updating

their own information in Locu’s database. When the user requests additional information

about a restaurant, we use Locu API queries to find a likely match to the corresponding

Yelp venue and parse restaurant menus and open hours, if either are provided.

Google Play Services

We used two components of Google’s Play Services API framework: The

Location API and the Maps API.

Location API

The Location API was used to determine the device’s most recent location

(effectively, the user’s current location) as a latitude and longitude coordinate, and

approximate the coordinate as an address string which is used as a parameter in the

Page 27: Füd5, A restaurant suggestion android application

27

Yelp API query. To accomplish this, we set the application permission

ACCESS_FINE_LOCATION in the Android Manifest, and included Google Play

Services Location API as a compile dependency. During execution, we create an

instance of the GoogleApiClient class to act as an interface between the application and

Play Services. Once a connection to the service is established, we first check that a

network connection is available and that Location Services is active in order to prevent

a runtime exception. Then, we call Location Services to obtain a Location object

containing the device’s latitude and longitude. Following this, we use the Geocoder

class to produce a list of addresses that approximately match the Location. After testing,

we found that the first address in the list is invariably accurate enough to pass as a

parameter to Yelp, so that is the address we use. The address is compiled into a single-

line String which is placed in the Location EditText field of the Main Activity. (If, for some

reason, an address cannot be approximated, the address string is empty. When the

user presses the “Fud Plz” button to obtain search results, they are prompted to

manually enter in an address.)

Though integrating use of the Location API into the application did not require a

large amount of code, we found that the need to check network and Location Services

connectivity prior to all operations involving the API presented some challenges during

early debugging.

Maps API

The Maps API was used to display a map in the results page activity with a pin

on the location of the currently displayed restaurant with accompanying business name

and address. The map is displayed is contained within a GoogleMap fragment in the

Result Page activity’s layout file. Use of the API is very straightforward: as soon as the

results of the Yelp API query are returned from RestaurantApiClient to the activity, the

GoogleMap view is set to center on the latitude and longitude of the first restaurant,

where we place a red marker which includes a snippet displaying the restaurant’s name

and address. The map is set to zoom level 14, which we found provided the best

overview of the general area, as the map shows nearby neighborhoods and major

streets. If the user is close enough to the location of the marker, the device’s location is

shown as a blue dot. The map is interactive and can be scrolled by pressing and

moving a finger across the screen. If the user wishes, s/he may center on the device’s

location by pressing the map’s crosshair icon, or open the Maps application to see a

full-screen view of the map. At the point where a user chooses to see the next

restaurant result and the Result Page is updated, the map is recreated and centered

about a new marker.

Page 28: Füd5, A restaurant suggestion android application

28

RestaurantApiWrapper library

Overview

We created a RestaurantApiWrapper library to provide methods and classes

necessary to perform Yelp and Locu API queries and access the resultant data. It exists

as a separate module which is a compilation dependency of the main application

module. Separating the library from the rest of the project provides the following

benefits:

1. The APIs used to obtain information about restaurants are abstracted away from

the rest of the project. In the case that an API is no longer utilized, methods used

to perform API queries and access data need not change, only the underlying

implementation. The API key values represent the only API-specific information

that needs to be passed to the wrapper.

2. The implementation of the API queries and the method by which data is parsed

and stored is hidden from the client. The client in this case is anyone working on

the application’s front-end code.

3. The RestaurantApiWrapper library can be used with other Android applications

as a module or a *.jar archive without the need to modify any code.

The diagram on the following page summarizes the relationship between classes in the

library and how they interact with the application.

Page 29: Füd5, A restaurant suggestion android application

29

Figure 22 - Relationship between RestaurantApiWrapper components and calling Activity

Page 30: Füd5, A restaurant suggestion android application

30

Implementation

The class RestaurantApiClient is the interface between the

RestaurantApiWrapper library and the application module. An activity in the application

can use RestaurantApiClient.Builder to instantiate a new RestaurantApiClient and

specify search type and parameters. The instance is called in a background task in

order to perform the query and return the results stored in an object of the appropriate

data type, either a Restaurant or RestaurantList. The activity can then use the object in

the foreground to display the results. Two types of searches are available: Search and

Business Search, described below. In addition, the MenuAndHoursExtension class

can be used statically to update a Restaurant object in place to supplement data

obtained through RestaurantApiClient (Yelp, in our implementation) with data from a

secondary API (Locu).

The Scribe library2 was used to facilitate OAuth requests to both the Yelp and

Locu APIs. RestaurantApiClient performs a token-signed OAuth GET request to the

Yelp API. The MenuAndHoursExtension, by contrast, uses a simple HTTP GET request

to the Locu API with the API key included in the request URL.

Both APIs returned results in the form of a JSON String which required parsing to

extract data. Fortunately, both Yelp and Locu provided documentation which described

the expected format of the results, including what data type would be appropriate to

store each field, and provided API consoles which provided some limited testing

functionality prior to implementing our parsing algorithms. After examining different

methods to interpret JSON strings, we opted to use Google’s built-in classes

JSONObject and JSONArray to manually parse the results. When parsing a JSON

object, we obtained an array of field names (keys) for a given hierarchy level using

JSONObject’s names() method, then passed each field name to a switch statement,

where each case corresponded to a field value we wished to parse. Each case

statement then read the field value as its expected data type. We found that this offered

better performance than using JSONObject’s has(fieldName) method, which must

iterate over the field names in a given level to find a matching name.

2 Scribe OAuth Java library: https://github.com/fernandezpablo85/scribe-java

Page 31: Füd5, A restaurant suggestion android application

31

Usage

The RestaurantApiWrapper module has Javadoc documentation which can be

found at the permalink: http://bitacoustic.net/raw_javadoc/

Key

Since the wrapper is abstracted away from the application as a dependency, it

does not have direct access to strings containing the Yelp API key, key secret, token, or

token secret, which are required to perform the OAuth query. To this end, we can

instantiate a YelpApiKey object, which contains these values, to pass as the required

parameter of the Builder. In our implementation, these key values are stored in a

resource file within module app.

public class ResultPageActivity extends AppCompatActivity

implements MenuNotFoundDialogFragment.MenuNotFoundDialogListener { YelpApiKey mYelpKey;

@Override

protected void onCreate(Bundle savedInstanceState) { ...

mYelpKey = new YelpApiKey( getApplicationContext().getResources().getString(R.string.yelp_consumer_key),

getApplicationContext().getResources().getString(R.string.yelp_consumer_secret), getApplicationContext().getResources().getString(R.string.yelp_token),

getApplicationContext().getResources().getString(R.string.yelp_token_secret) ); ...

} }

Figure 23 - Instantiating a YelpApiKey object to pass to RestaurantApiClient

Business Search

Using business search, we can obtain a Restaurant object which contains useful

information about a specific restaurant. Aside from the API key, the only required

parameter is a unique Yelp ID. To obtain a Restaurant object, we instantiate a new

RestaurantApiClient object using the Builder and call the method getRestaurant() in a

background task:

Page 32: Füd5, A restaurant suggestion android application

32

private class RestaurantTestActivity extends Activity { ... protected Restaurant mRestaurant; ... @Override protected void onCreate(Bundle savedInstanceState) { ... String id = "new-tsing-tao-restaurant-san-francisco"; new RestaurantAsyncTask.execute(id); } private class RestaurantAsyncTask extends AsyncTask<String, Void, Restaurant> { @Override protected Restaurant doInBackground(String... params) { Restaurant response = null; String passedId = params[0]; try { response = new RestaurantApiClient.Builder(mYelpApiKey) .id(passedId) .build().getRestaurant(); } catch (JSONException | IOException e) { // handle JSON parsing exceptions } return response; } protected void onPostExecute(Restaurant response) { mRestaurant = response; } } ... }

Figure 24 - Obtaining a Restaurant object with RestaurantApiClient

The Restaurant object is now available for use elsewhere in the calling activity. It should

be noted that the RestaurantApiClient can throw an exception due to a JSON parsing

error; this can act as a flag to try the request again or perform some other operation to

recover gracefully from an error.

Business Search functionality was not utilized in the release version of the

application but a demonstration of its use can be seen in the RestaurantTestActivity in

app/src/java/tests.

Search

Using search, we can obtain a RestaurantList object which contains restaurants

near a specified location, sorted in order by shortest distance, highest rating, or best

match to optional search terms. A number of other optional parameters are available to

refine the search, as specified in the Javadoc. To obtain a RestaurantList object, we

follow the same methodology as for a Business Search but use the RestaurantApiClient

method getRestaurantList().

The following code is from the actual application and shows a network

connectivity check before the call is made. This is necessary to ensure the application

does not crash. Also, since the AsyncTask (background task) is available as an Activity-

Page 33: Füd5, A restaurant suggestion android application

33

scope variable, we can check elsewhere that the task has been completed before

performing other functions which are dependent on the data in the RestaurantList:

public class ResultPageActivity extends AppCompatActivity implements MenuNotFoundDialogFragment.MenuNotFoundDialogListener { GetResultTask getResultTask; RestaurantList mResultList; // user input parameters passed as extras from calling Activity String location, searchTerm; int maxRadius; double minRating; ... @Override protected void onCreate(Bundle savedInstanceState) { // ... store extras from calling Activity ... // start background activity to get the results if (ServiceUtil.isNetworkAvailable(this)) { getResultTask = new GetResultTask(); getResultTask.execute(); // display a "Getting info..." PopupWindow } else { // Close the results page immediately if there is no network connectivity; to // the user it will appear as if the results page never opened ToastUtil.showShortToast(this, getString(R.string.toast_network_unavailable)); finish(); } } private class GetResultTask extends AsyncTask<String, Void, RestaurantList> { @Override protected RestaurantList doInBackground(String... params) { try { return new RestaurantApiClient.Builder(mYelpKey) .location(location) .sort(RestaurantApiClient.SortBy.BEST_MATCH) .term(searchTerm) .radiusFilter(maxRadius) .build().getRestaurantList(); } catch (Exception e) { e.printStackTrace(); return null; } } protected void onPostExecute(RestaurantList result) { mResultList = result; // close the PopupWindow ... } } }

Figure 25 - Obtaining a RestaurantList object from RestaurantApiClient

Note that, as with the Business Search, RestaurantApiClient can return a number of

exceptions, namely JSONException and IOException during JSON parsing, as well as

ParameterRangeException due to a search parameter outside of its allowable range.

The possibility of a ParameterRangeException should entice those calling

RestaurantApiClient to perform a sanity check on the values of user-supplied

parameters. Examples of possible out-of-range parameters include an integral sort

Page 34: Füd5, A restaurant suggestion android application

34

order value other than the three available in the Yelp API (0 for best match, 1 for

distance, and 2 for highest-rated), or a search radius greater than 40,000 meters.

MenuAndHoursExtension

MenuAndHoursExtension accepts a Restaurant object populated with data from

the primary restaurant API (Yelp) and queries a secondary API (Locu) database for a

match. It has several methods which may be called statically to update the Restaurant

object in places with any available additional information.

getId() / getIdIfHasMenu(): Attempts to get the Locu ID for the given Restaurant,

using the Restaurant's geolocation, first word of the business name, street

address, and postal code.

updateFromMatchedId(): Parse information about a Locu venue and add it to

the Restaurant: open hours and menus, if either are available.

update() / updateIfHasMenu(): Attempts to match the specified Restaurant to a

venue in Locu's database, extracting menus and open hours for the restaurant if

either are available. These methods are essentially a combination of the two

methods above.

Similarly to RestaurantApiClient, the secondary API (Locu) key must be passed to

MenuAndHoursExtension. Then, the extension may be called from within a background

task initiated by the calling activity. The following example shows the extension being

used to query Locu for a match to a Yelp-populated Restaurant and display a dialog

containing the restaurant menus, if available:

public class LocuMenuTestActivity extends Activity implements MenuNotFoundFragment.MenuNotFoundDialogListener { Restaurant mRestaurant; ... private class DisplayMenuTask extends AsyncTask<String, Void, Restaurant> { @Override protected Restaurant doInBackground(String... params) { mRestaurant = new Restaurant(); // contains only default parameters MenuAndHoursExtension menuExtension = new MenuAndHoursExtension (mLocuKey); menuExtension.updateFromMatchedId(mRestaurant, params[0]); return mRestaurant; }

Page 35: Füd5, A restaurant suggestion android application

35

@Override protected void onPostExecute(Restaurant restaurant) { // show menu dialog or handle menus not found if (mRestaurant.hasMenus()) { mTxtDebug.setText("Loading menu..."); DialogFragment displayRestaurantMenus = DisplayRestaurantMenusFragment.getInstance(restaurant); displayRestaurantMenus.show(getFragmentManager(), "menus"); } else { mMenuNotFoundDialog = new MenuNotFoundDialogFragment(); menuNotFoundDialog.show(getFragmentManager(), "menuNotFound"); } ... } } ... }

Figure 26 – updating a Restaurant with information from Locu via the MenuAndHoursExtension

If a match was found, any of the following data may become available for access, in

addition to any data already obtained from Yelp: the restaurant’s open hours, menus

(e.g. the breakfast, lunch, and dinner menus), Facebook URL, and Twitter ID.

Data Types

Restaurant

The Restaurant class is a data type holding information about a single business

parsed from both the Yelp and Locu APIs. While an “empty” Restaurant can be

instantiated, it is not particularly useful unless it has been received as the result of an

API call through RestaurantApiClient. In this case, it is populated with data from Yelp

which can be obtained through a number of getter (accessor) methods which return the

data in a format appropriate to a given field. For example, a business name is returned

as a String, a website URL or phone number is returned as a Uri object that can be

passed to an Intent, a business address is returned as an Address object from the

Google API, and so forth. No setter (mutator) methods are provided. This ensures the

application’s contract with Yelp: we can be sure the data in a Restaurant comes from

the API, and not another source. Additional data members are provided for use by the

MenuAndHoursExtension, which updates the Restaurant with information obtained by

the Locu API. Here are some usage examples:

Page 36: Füd5, A restaurant suggestion android application

36

String name = mRestaurant.getBusinessName(); if (mRestaurant.hasImageUrl()) { displayImage(mRestaurant.getImageUrl()); } // dial the business's phone number Intent intent = new Intent(Intent.ACTION_DIAL); intent.setData(mRestaurant.getPhoneDialable()); startActivity(intent);

Figure 27 - Restaurant object getter examples

For abstraction purposes, it is not necessary for the user to know which API was

used to obtained the information so much as know what information is available. To this

end, primitive data types are initialized consistently such that they are empty, in the

case of a String; have a negative value, in the case of a number; or are null, in the case

of an object. If a data member was not populated from the result of an API query, it

retains its initialized state. In a number of cases, methods which return booleans are

provided to evaluate whether information is available, such as hasMenus(),

hasCategories(), etc.

Certain information obtained from Yelp and Locu exhibits complexity such that

custom data types were created for ease of access. Such include the YelpCategory,

which is a pairing of display name and Yelp internal identifier; OpenHours, which

contains an ArrayList of open hours ranges for each day of the week which can be

rendered in 12-hour or 24-hour format; and Menus, an object which can hold multiple

restaurant menus (e.g. breakfast, lunch, and dinner) containing sections, subsections,

subsection text, item descriptions and prices, and so forth.

Currently, most data returned in a Yelp API query about an individual business is

parsed and stored in the Restaurant object, with the most notable exceptions being gift

certificate availability and details, as well as details of special deals offered through

Yelp.

RestaurantList

A RestaurantList contains two components: a list of Restaurant objects (as

described above) and a MapBounds object. MapBounds provides a suggested center

and height and width for a map encompassing all the restaurants on the list. Yelp

returns this information for all searches producing one or more restaurants as a result.

As an extension of this, RestaurantList automatically recalculates the values in the

MapBounds object when a Restaurant is manually added to the list by the user.

RestaurantList implements the majority of methods from ArrayList to allow

addition and removal of Restaurants. These are some examples where familiar

methods are used:

Page 37: Füd5, A restaurant suggestion android application

37

mRestaurant = mRestaurantList.get(1); mRestaurantList.add(mRestaurant); mRestaurantList.add(1, mRestaurant); int listSize = mRestaurantList.size(); Iterator it = mRestaurantList.iterator(); mRestaurantList.removeAll(someCollection); Boolean hasRestaurant = mRestaurantList.hasRestaurant(mRestaurant);

Figure 28 - RestaurantList getter and setter examples

Here are some examples of methods created specifically to accommodate locating and

reordering restaurants in the list:

// search list for restaurant having specified Yelp ID Boolean hasRestaurant = mRestaurantList .hasRestaurant(("new-tsing-tao-restaurant-san-francisco"); // demote a Restaurant 2 places in the list mRestaurantList.demote("some-restaurant-id", 2); mRestaurantList.demote(someRestaurant, 2); // promote a Restaurant 2 places in the list mRestaurantList.promote("some-restaurant-id", 2); mRestaurantList.promote(someRestaurant, 2);

Figure 29 - RestaurantList matching and reordering method examples

Serialization of Data

RestaurantList and Restaurant objects are serializable. While as of this writing

Yelp generally prohibits users from caching restaurant data3, serialization may be useful

to pass the objects from an Activity to a Dialog, a Dialog to an Activity, Activity to

another Activity, etc. Here is an example where serialization is used to pass a

Restaurant from an Activity to a DialogFragment. The relevant code in the

DialogFragment is:

public class DisplayRestaurantMenusFragment extends DialogFragment { Restaurant mRestaurant; // the restaurant for which to display the menu ... public static DisplayRestaurantMenusFragment newInstance(Restaurant r) { DisplayRestaurantMenusFragment f = new DisplayRestaurantMenusFragment(); Bundle args = new Bundle(); args.putSerializable("restaurant", r); f.setArguments(args); return f; }

3 Yelp API Terms of Use: https://www.yelp.com/developers/api_terms

Page 38: Füd5, A restaurant suggestion android application

38

@Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); // load the restaurant argument mRestaurant = (Restaurant) getArguments().getSerializable("restaurant"); } }

Figure 30 - Serialization of data between Activity and DialogFragment – DialogFragment code

The relevant code in the calling Activity is: public class LocuMenuTestActivity extends Activity implements MenuNotFoundFragment.MenuNotFoundDialogListener { Restaurant mRestaurant; ... private class DisplayMenuTask extends AsyncTask<String, Void, Restaurant> { @Override protected Restaurant doInBackground(String... params) { mRestaurant = new Restaurant(); // contains only default parameters LocuExtension locu = new LocuExtension(mLocuKey); locu.updateFromMatchedLocuId(mRestaurant, params[0]); return mRestaurant; } @Override protected void onPostExecute(Restaurant restaurant) { // show menu dialog or handle menus not found if (mRestaurant.hasLocuMenus()) { mTxtDebug.setText("Loading menu..."); // create an instance of DisplayRestaurantMenusFragment with // the restaurant result of doInBackground() as an argument DialogFragment displayRestaurantMenus = DisplayRestaurantMenusFragment.newInstance(restaurant); displayRestaurantMenus.show(getFragmentManager(), "menus"); } else { // handle menu not found } ... } } }

Figure 31- Serialization of data between Activity and DialogFragment – Activity code

Ideas for Refinement

Better matching of Yelp listings to their Locu counterparts

As described previously, the MenuAndHoursExtension attempts to find a Locu

venue by using the first word of the restaurant name as well as the restaurant’s street

address, postal code, and latitude and longitude in a Locu API search query; in addition,

we assume that the first venue in a non-empty result list is the match. This produces

correct matches often enough for the feature to be viable, even if the availability of a

corresponding match in Locu’s database to a given Yelp business is limited. (We find

that Locu’s data is not as comprehensive since it is not end-user sourced.) Admittedly,

Page 39: Füd5, A restaurant suggestion android application

39

we find that the current algorithm can sometimes fail to find a matching Locu venue

even if one exists and, very rarely, produce an erroneous match.

To further maximize the match success rate and eliminate the occasional

erroneous match, we could apply further checks to compare the Yelp business with

Locu’s list of potential matches. For example, approximate string matching techniques4

could be employed to compare the names of the restaurants in Locu’s list choose the

best-matching restaurant within some degree of confidence, even if it is not the first

result. Several Java libraries such as SimMetrics5 exist to find a degree of similarity

between two strings using such metrics as the Levenshtein distance, though this may

exclude restaurants where their name recorded in the Yelp and Locu databases differ

by a whole word, such as “Restaurant”. Even so, this may prove to be more reliable

than simply comparing two restaurant names based on just the first word. This is

especially true if that word is common, such as “The”, or two nearby restaurants

coincidentally share a first (or any) word in common and the provided latitude and

longitude are not enough to favor the correct result.

In addition to business name, we could apply an approximate string matching

technique to the street address as well. This would allow us to iterate over Locu’s

returned list of possible matches and cross-reference the business name with the

address. The Locu venue having the business name and address pair exhibiting the

highest degree of similarity with information provided by Yelp should, in theory, be the

correct match. Only with implementation and thorough testing would be know if this

technique actually increases match success.

Loose coupling of search and client

In the current implementation, RestaurantApiClient.Builder accepts a number of

parameters regardless of whether they apply to either a Business Search or a Search,

and then returns a data type corresponding to the result of one of these search types

based on the use of either the method getRestaurantList() or getRestaurantById().

Given further development time, the search and parsing of the results could be

abstracted away from RestaurantApiClient in the form of a class corresponding to a

Business Search, a Search (labeled LocalSearch in the diagram, to distinguish it from a

Search abstract class), or indeed any type of search provided by the API used. (For

example, Yelp also provides a Phone Search which was not implemented for this

project.) The following diagram may be helpful to visualize this concept.

4 https://en.wikipedia.org/wiki/Approximate_string_matching 5 SimMetrics: https://github.com/Simmetrics/simmetrics

Page 40: Füd5, A restaurant suggestion android application

40

RestaurantApiClient could receive the desired Search class as a parameter and

call the class’s search() method to obtain an Object of the appropriate type and return it.

Such a call might look like the following:

RestaurantList rList = (RestaurantList) new RestaurantApiClient(key, new LocalSearch() .location(“Los Angeles”).searchTerm(“diner”).build()).getResult();

Figure 33 - Possible construction of RestaurantApiClient call with search type abstraction

Conclusion

The RestaurantApiWrapper library functions as an adapter between the

application’s front-end code and the Yelp and Locu APIs. It demonstrates use of object-

oriented principles and a Builder pattern. Though not a Factory in the sense of taking

advantage of polymorphism, RestaurantApiClient can produce objects of various types.

The library demonstrates encapsulation of restaurant data and loose coupling to

separate implementation details from the rest of the application. Through further

refinement, the library could be more-easily extensible to accommodate other search

types. By adding further extensions, additional similar APIs could be used.

Figure 32 - Search type abstraction

Page 41: Füd5, A restaurant suggestion android application

41

Restaurant Selection Algorithm

The Restaurant Selection Algorithm utilizes the green, yellow, and red lists—the

user’s Restaurant History—in conjunction with randomization to sort the list of

restaurants queried from Yelp such that the first result in the list is likely to be a good

match for the user. Figure 37 on pg. 43 shows the Restaurant Selector Algorithm in

action.

To describe the algorithm in detail we find it best to describe each step taken

along with the specific code used.

Step 0: Query Yelp for a list of restaurants

We refer to this as “Step 0” since this is where the initial list is obtained. The

order of the restaurants in the resultant RestaurantList is unimportant, as we will be

reordering the list.

private class GetResultTask extends AsyncTask<String, Void, RestaurantList> { @Override protected RestaurantList doInBackground(String... params) { try { return new RestaurantApiClient.Builder(mYelpKey) .location(location) .sort(RestaurantApiClient.SortBy.BEST_MATCH) .term(searchTerm).radiusFilter(maxRadius) .build().getRestaurantList(); } catch (Exception e) { return null; } } ... }

Figure 34 – Restaurant Selector Algorithm: querying Yelp for a list of restaurants

Step 1: Filter unwanted restaurants

Specifically, we remove restaurants that the user has added to the red list by

pressing the “Always Ignore” button in the Result Page, and those restaurants whose

rating is less than the minimum rating indicated before the search is performed. In the

latter case, since Yelp does let us filter out restaurants below a certain rating, we must

apply the filter to the results.

for (int i = 0; i < mResultList.getSize(); ) { if (mResultList.getRestaurant(i).getRating() < minRating || db.isRestaurantInList(mResultList.getRestaurant(i), Constants.RED_LIST)) { Restaurant removed = mResultList.removeRestaurant(i); if (removed == null) i++; } else i++; }

Figure 35 – Restaurant Selector Algorithm: filtering unwanted restaurants

Page 42: Füd5, A restaurant suggestion android application

42

Step 2: Randomize & refine restaurant sort order

Each restaurant in the list is assigned a weight which determines the final sorted

order of the list of restaurants used to present suggestions to the user. For each

restaurant, this weight is initially a random integer between 1 and 100. For green- and

yellow-listed restaurants, this weight is further refined with a multiplier which influences

its position in the final list.

Green-listed restaurants are given a constant multiplier of 1.15. That is, they are

promoted relative to the otherwise random order.

In contrast, yellow-listed restaurants are given a multiplier which varies linearly

with the UNIX timestamp indicating when the restaurant was added to the list. The end

result is that restaurants just added to the yellow list are demoted relative to the

otherwise random order by 40%, whereas restaurants added to the yellow list nearly a

week ago are not demoted relative to the otherwise random order. (The Splash Screen

activity automatically clears restaurants from the yellow list which were added more

than a week before the current time.)

for (int i = 0; i < mResultList.getSize(); i++) { randomNum = rand.nextInt((100 - 1) + 1); Restaurant r = mResultList.getRestaurant(i); if (db.isRestaurantInList(r, Constants.GREEN_LIST)) { randomNum *= 1.15; } else if (db.isRestaurantInList(r, Constants.YELLOW_LIST)) { Timestamp timestamp = Timestamp.valueOf(db.getRestaurantTimeStampFromList(r, Constants.YELLOW_LIST)); long timeElapsed = System.currentTimeMillis() - timestamp.getTime(); final long ONE_WEEK_IN_MILI = 604800000; randomNum *= (0.6 + 0.4 * timeElapsed/ONE_WEEK_IN_MILI); } mResultList.getRestaurant(i).setWeight((int) randomNum); }

Figure 36 – Restaurant Selector Algorithm: randomizing and refining restaurant sort order

Step 3: Present restaurants to user in non-increasing weight order

The first restaurant displayed to the user will be the restaurant in the list having

the highest weight. Internally, that restaurant is removed from the underlying ArrayList

of Restaurants in the RestaurantList object before being presented to the user, so the

restaurant in the modified ArrayList having the highest weight will be the next result.

This fact is useful in that we can look ahead and pre-load the next restaurant’s Yelp-

provided image.

Page 43: Füd5, A restaurant suggestion android application

43

Figure 37 - Demonstration of restaurant selection algorithm on HTC One M7 (5”)

Page 44: Füd5, A restaurant suggestion android application

44

Data Storage

Shared Preferences

Introduction

We utilized Android’s SharedPreferences feature to store data in Key Value

pairs. This approach allows us to easily access data faster without having to make

database queries. Our Application utilized SharedPreferences by defining and storing

default application settings.

SharedPreferences also powers the application’s SharedPreferences feature to

let the end-user define default values for the application:

Data stored

Key Value Info

hasAgreedtoEula boolean When the user chooses to agree or disagree to the end user license agreement

defaultSearchRadius float The search radius where the application will obtain restaurants from

defaultMinStar float The minimum star rating for a restaurant to look for

lastGreenRestaurantTimestamp float The timestamp that determines when to display a restaurant feedback after choosing to go to the restaurant

lastGreenRestaurant String A name the last restaurant that the user chose to go to

Figure 38 - Data stored in application's Shared Preferences file

SQLite

Introduction

We leveraged Android’s built-in SQLite database feature to store more structured

data as compared to Key-Value pairs. For example, we wanted to use SQLite to store

data that powers our Selector algorithm which promotes and demotes restaurant

results. The SQLite table allowed us to store the restaurant’s Yelp business ID, as well

as the timestamp it was inserted in the database. In addition, SQLite’s structured data

Page 45: Füd5, A restaurant suggestion android application

45

allows us to extend the database to store more relevant restaurant data coming from

Yelp API that we might need to know about in the future.

Data stored

List Data

Green Restaurants where the user has eaten.

Red Restaurants that the user has chosen to ignore. These will not show up on subsequent searches.

Yellow Restaurants that the user has chosen to check out later.

Figure 39 – Application’s SQLite database tables

Conclusion

We utilized two of the five different ways to store data in Android6: SharedPreferences

and SQLite. Storing data in SharedPreferences is ideal for default application settings

because it forces data to be stored in key-value pairs making it faster to access when

compared to SQLite. And on the other hand, while SQLite can allow storage of more

complex and more structured data, it can be slower after adding more rows and

columns.

6 Android Storage Options: http://developer.android.com/guide/topics/data/data-storage.html

Page 46: Füd5, A restaurant suggestion android application

46

Utilities

Constants

Constant values used throughout the application were defined as static variables in a

class named Constants. Such values included database table numbers for the green,

yellow, and red lists, as well as strings representing the field names of stored Shared

Preferences. This served to make the main application code more readable. For

example: db = new dbHelper(this, null, null, Constants.RESTAURANT_LISTS_TABLE_ID) versus db = new

dbHelper(this, null, null, 1) –or– db.deleteRestaurantFromList(r, Constants.YELLOW_LIST); versus

db.deleteRestaurantFromList(r, 2);.

ServiceUtil

Since it is necessary to check for network connectivity prior to making any API call, and

it is necessary to check that Google Play Location Services is enabled prior to obtaining

the device’s current location, we created a class with static methods to check these

conditions.

ServiceUtil.isNetworkAvailable() checks the provided Context (usually, an

Activity or DialogFragment) to determine whether the Android Connectivity Service is

available and whether the device is connected to the network. If so, the method returns

true.

ServiceUtil.isLocationServicesOn() checks the Android Location Manager to

determine whether the GPS location provider and the network location provider are

available. If either are available, this is sufficient for Location Services to retrieve the

device’s last known location, and so the method returns true.

ToastUtil

During development it is necessary to display of feedback and/or information that

is needed to debug a specific portion of the application. Since developers are going to

need a lot of feedback, they need to write feedback code sparsely throughout the whole

application code base and can easily make code harder to read. In order to display such

in a clean and well defined manner, it is good to use Toasts. ToastUtil is a utility class

that makes writing toasts easier write therefore making the application’s code base

easier to manage and more loosely coupled.

Instead of writing: Toast.makeText(getActivity, “I am a toast”, TOAST_Length.SHORT).show(); one can

write: ToastUtil.showShortToast(getActivity, “I am a toast”); instead.

Page 47: Füd5, A restaurant suggestion android application

SECTION 4: CONCLUSION & FUTURE GOALS

Page 48: Füd5, A restaurant suggestion android application

48

Future stretch goals

Food Niche

Implementation

Food Niche is a feature that allows the user to collaborate with the application's

algorithm by actively participating in its restaurant selection training. In order to

implement, we need to utilize Java’s TreeSet data structure to create a collection of

possible food niches that the end-user might be interested in. The food niche collection

will be appended and modified on the fly with restaurant category values--obtained from

either Yelp or Locu API--on the green list, which allows the Selector class to learn which

restaurants the user tends to put on the green list. Then, the collection can be modified

via a Food Preferences dialog where the user can downvote and upvote niches. This

allows the user to collaborate with the Selector class to give more refined results based

on the user’s tastes. Finally, the collection can also be reset using the Application

Settings dialog where it wipes the entire collection of niches

Advantages

Food niche allows the user to maximize the accuracy of restaurant suggestions

because it allows both the application and the end-user to collaborate hand in hand to

build better suggestions.

Notes

We will use TreeSet to store food niches because sets do not allow duplicates

and it allows ordering of items as compared to HashSet. Since there are only a handful

of food niches (< 100) that user may care about so the time complexity for its ‘add’,

‘remove’, and ‘contains’ methods, O(log(n)), should be pretty trivial. Also, trees also

allow the application to “weigh” niches based on end-user’s upvotes or downvotes

under Food Preferences.

Push Notifications

Advantages

Push notification is a possible feature in our application that we can implement to

provide better user experience by provides another layer of interaction apart from what

the application already offers. Notifications drive the user to use the application even

more through notifications that drive retention such as sending a message when there is

a new restaurant nearby, or when the user is in a new location where there are lots of

restaurants nearby. In addition, notifications can also ease the user experience by

Page 49: Füd5, A restaurant suggestion android application

49

providing notifications if there is a new version of the application where bugs are fixed or

when new integrations have been added. Finally, notifications overall make the

application “smarter” by responding directly to events that happen both inside the

application (when the user clicks a specific button) or outside the application (when user

is nearby a restaurant)

Notes

Push notifications are event driven (i.e.: when you get an e-mail once you

subscribe to a newsletter), and must be called upon execution of a certain event. Some

push notifications can be delayed such as a notification that shows a “Rate my

restaurant” notification 30 minutes after the user presses “Go to this restaurant. Push

notifications are an integral part of any modern-day application.

Food Pairing

Implementation

Food pairing is another integral feature that can be useful for the application in

the future. By using the API available at http://developer.foodpairing.com/, we can

implement a way to suggest popular food pairs in the menu. By mining the Locu

restaurant menu as well as Yelp's top rated comments, we can identify popular food

choices by previous restaurant customers. Once all the food choices are obtained for

the specific instance of the restaurant object, we can store the choices in a data

structure such as a Map where we can begin pairing food choices using the Food

Pairing API.

Advantages

Just like push notifications and food niche features, food pairing allows the

application to become smarter and offer better user experience for the end-user. Not

only it suggests restaurants to go to, it also suggests possible appetizers, main entrees

and desserts using food pairing algorithms.

Notes

Although the data is available using designated APIs, string matching and

processing can still be a challenge. In order to handle this, it is necessary to utilize 3rd

party APIs such as SimMetrics.

Page 50: Füd5, A restaurant suggestion android application

50

Monetization

Early on in the program’s life, we would simply use banner ads on the main filter

page where there is room for it. An option can be offered in the program’s settings to

pay a small fee to disable ads, and expand the number of restaurant recommendations.

Later in its life, however, when the application becomes more popular, we could

have sponsored recommendations in lieu of ads, which would have a higher weight in

the randomizer. A higher weight means that the restaurant is more likely to become one

of the first results on the restaurant result page. This would be visible to the user as a

“Sponsored Result”, though users would still be able to add the restaurant to the ignore

list, if desired.

Page 51: Füd5, A restaurant suggestion android application

51

What We Would Do Differently Next Time

Had this team the opportunity to attempt this project all over again, knowing what

we now know, there are a few things we would have done differently. In the very

beginning, we all met to discuss our strengths and weaknesses. Following that, we

should have began listing what kinds of tasks we needed to accomplish and assign said

tasks to certain team members, or even pairs of team members. When a task was

completed, the team member who completed it could have checked to see if there was

any currently active task that he could have joined, instead of immediately moving on to

a new task. Our original focus was very vague, and our roles weren’t well enforced. As

a result, we’d often find ourselves either working on the same task or we’d skip around

and work many different tasks at once. That created a bit of a problem in that the more

experienced coders would finish tasks very quickly and leap ahead of the less

experienced individuals. Towards the end of the project, however, this was addressed

and we were much closer to attaining a better split of the workload.

Another aspect of the project that could have been handled much more neatly

was the weekly scrums. We lacked a proper focus during our scrums and would often

go on tangents during the process. These tangents were always relevant to our project,

but they were better suited for post-meeting discussion. This resulted in scrums that

should have lasted 5-10 minutes lasting well over 15 minutes. This became very

apparent when we scrummed with Marc (the ‘Boss’ of the ‘company’) because he would

control the pace well, and our meetings were extremely quick and efficient. To improve

our scrums, we should have had the note-taker for the meeting, or the team leader,

Alex, be the one to control the flow, to ensure that everyone got a chance to speak.

Team members could have all had notebooks in which they would take note of what

topics they’d want to elaborate on post-meeting, in order to prevent getting sidetracked

during the meeting.

Something that was an issue early on in our development process was

understanding Github and its integration with Android Studio. We should have brought

our laptops to a meeting and organize our Github and Android Studio integrations,

ensuring that we all had the same settings in order to prevent compatibility issues

arising from pushing and pulling each other’s code bases.

Page 52: Füd5, A restaurant suggestion android application

52

Bibliography/Resources

3rd Party Tools

Tool Purpose URL

Stack Overflow

General code help http://stackoverflow.com/

Slack Messaging, project management

http://slack.com/

Github Version Control http://github.com/

Github Wiki Documentation https://github.com/sfsucsc413/t5/wiki

Android Studio

Development Environment, Source Control

https://developer.android.com/sdk/index.html

EULA Generator

EULA Generation http://kuikie.com/tools/eula-generator/

String Formatter

Formatting text http://www.freeformatter.com/html-formatter.html

Licenses

Tool URL

Google Maps https://developers.google.com/maps/terms

Yelp https://www.yelp.com/developers/api_terms

Locu https://dev.locu.com/terms/

Android https://source.android.com/source/licenses.html

Android Studio/IntelliJ

http://blog.jetbrains.com/idea/2013/05/intellij-idea-and-android-studio-faq/#comment-4939

Gradle https://gradle.org/license/

SQLite https://www.sqlite.org/copyright.html

Page 53: Füd5, A restaurant suggestion android application

SECTION 5: PRESENTATION SLIDES

Page 54: Füd5, A restaurant suggestion android application

54

During the final week of class, each group in the class gave a brief ~10-minute

presentation about their app. The presentations explained how the apps worked, both

as a user, and how they worked on a technical level.

Figure 40 - Slide 1

Page 55: Füd5, A restaurant suggestion android application

55

Figure 41 - Slide 2

Figure 42 - Slide 3

Page 56: Füd5, A restaurant suggestion android application

56

Figure 43 - Slide 4

Figure 44 - Slide 5

Page 57: Füd5, A restaurant suggestion android application

57

Figure 45 - Slide 6

Figure 46 - Slide 7

Page 58: Füd5, A restaurant suggestion android application

58

Figure 47 - Slide 8

Figure 48 - Slide 9

Page 59: Füd5, A restaurant suggestion android application

59

Figure 49 - Slide 10

Figure 50 - Slide 11