NorfolkTouring is an Android application that presents various locations of interest in Norfolk, Virginia.
Its primary purpose is to showcase various features of Android - including RecyclerViews, DrawerLayouts, Adapters, Fragments (extensively used), click listeners, AsyncTasks, Handlers (used for automatic image cycling), Services, MediaSessions (including MediaStyle notifications that allow control of media playback as in apps like Spotify), Widgets, Menus, SharedPreferences, Jobs (using Firebase JobDispatcher to issue recurring notifications), ContentProviders, and more.
Location data is stored in a SQLite database, and SQL queries are used to manage it. Data that may not be cached indefinitely - namely, data retrieved with APIs such as the Google Places API - is not stored in the database.
Some APIs used in this project include the Google Maps API (both for Web and Android - using both URI queries and the Android API), the Google Places API (again, using both URI queries and the Android API), the YouTube Android Player API, the Fused Location Provider API, and the Volley networking library. ExpandableLayout by AAkira provides animation to the expandable feature items in the detailed views for tour locations.
UI tests are conducted with the Espresso testing framework. These tests can be found in app/src/androidTest.
See a demo of this here!
The application opens with an introductory video and navigation instructions. The video can be controlled with the play/pause button on the video pane itself, but it can also be played, paused, and restarted through a MediaStyle notification with a musical note icon.
There is a drawer on the left that may be swiped open from the left side of
the screen to the right side. Clicking on any of the drawer elements will open a list of tour locations
(RecyclerView
populated by an Adapter
) - displaying information such as the location name,
rating (from Google reviews), current open status, and distance (updated in real-time).
It is also possible to open a view of a location on a map by clicking on the nested View
with the text "Google Maps View". Directions to a location can be obtained
by clicking on the nested View
with the text "Plan Route"
(this opens the user's preferred map application with an implicit Intent
).
Clicking on the tour location View
(e.g. clicking on the image) will open a detailed
view of that location. This view shows additional information, such as the operating hours,
website, address, contact information, and a description for the corresponding location.
Both the "Chosen Images" and the "Images from Google" can be clicked on
to enlarge them and allow manual cycling.
There is also a widget that lists the categories of touring locations if it is large enough. Clicking an element of the list opens the app and shows the corresponding set of tour locations.
Notifications regarding the nearest location are issued every 5 to 10 minutes. Only locations that have been loaded so far are considered - i.e. only the categories opened since the app launched. Clicking on these notifications shows the appropriate group of tour locations in the app.
The settings menu can be accessed from the 3 vertical ellipses in the top right corner.
Wifi and cell data usage can be toggled, which stops location updates and changes View
visibility and contents accordingly. Notifications may be toggled as well.
NorfolkTouring
: Used to acquire a static instance of the application Context
through
getApplicationContext()
, defines some API keys, and provides functions for
setting the ActionBar
title.
MainActivity
: Initializes a Google API Client, contains and initializes
the Navigation Drawer (a DrawerLayout
), launches the IntroductoryFragment
, and
receives location updates from Location/LocationService
if wifi and cell data usage is enabled.
IntroductoryFragment
: Contains and initializes a YouTubePlayerFragment
and the
introductory text. Contains a MediaSession
(this is often part of a containing Activity
rather than a Fragment
) that allows a YouTube video player (YouTubePlayer
) to be controlled by
a MediaStyle notification (used by media playback applications such as Spotify).
TourLocation:
All information regarding a tour location is stored in a object of this type.
TourLocation.LocationFeature
: A feature for a TourLocation
. Has a name, description, and images.
TourLocationListFragment/TourLocationListFragment
: The description of a list of
TourLocation
objects. Subclasses only define the TourLocation
objects that are to be displayed.
The list is a RecyclerView
rather than a ListView
to only store visible views in memory.
TourLocationDetailFragment
: The detailed description of a TourLocation
. Cycles resource images
and Google images (obtained asynchronously through Utils/PlacesUtils
). Allows resource images
and Google images to be viewed in an enlarged view that allows manual cycling of images
in forward and reverse with arrows on both sides of the screen. Features may be expanded and
collapsed with animated views by clicking on them. Feature images are also automatically cycled.
All image cycling in a TourLocationDetailFragment
stops and starts with its lifecycle events.
MainActivity.DrawerItemClickListener
: Replaces the main view with the Fragment
(a TourLocationListFragment
)
corresponding to a clicked drawer item. The Fragment
launched will be one of the following:
MilitaryFragment
, MuseumsFragment
, OtherFragment
, ParksFragment
, or RestaurantsFragment
.
TourLocationListFragment.TourLocationClickListener
: Replaces the main view with a TourLocationDetailFragment
displaying
more information than the TourLocationListFragment
.
NavigationIconClickListeners.DirectionsIconClickListener
: Uses an implicit Intent
to launch a
map application (e.g. Google Maps) that plots a path between
the device's location and the location of the corresponding TourLocation
.
NavigationIconClickListeners.MapIconClickListener
: Opens a Google Maps view, places a marker
at the location of the corresponding TourLocation
, and zooms to it.
Also allows navigation to the device location with a button.
Data/TourLocationCursorAdapter
: Used by TourLocationListFragment
to fill a list of
TourLocation
objects with data from a Cursor
provided by TourLocationContentProvider
.
LocationService
: A Service
subclass for obtaining location updates (serves as a singleton).
The LocationService
stops and starts with the Activity
lifecycle, which includes stopping and
restarting location updates (e.g. location updates stop being requested when the screen is
turned off). Uses the Fused Location Provider API.
Utils/PlacesUtils
: Records Place IDs in the Google Places API for the locations presented
in the application. Allows retrieval of images and information for locations via AsyncTask
subclasses also defined in Utils
.
Utils/PhotoTask
: Retrieves 10 photos for a location using the Google Places API for Android.
Utils/AttributedPhoto
: Displaying the photos retrieved via the Google Places API requires
photo attribution. This class contains an image and its attribution.
Utils/LocationsByIdsTask
: Not used, but shows how to retrieve latitude and longitude for a place
from the Google Places API for Android (no URI queries here).
Utils/InfoByIdsTask
: Acquires the location (latitude and longitude), hours of operation,
rating (Google reviews), and the website for TourLocation
objects using URI queries and Volley
.
Widget/WidgetProvider
: Draws and updates widgets based on their options (e.g. height and width).
Smaller widgets just have the application background. Larger widgets also have a GridView
.
Widget/GridWidgetService
: Populates a larger widget's GridView
with the categories
of tour locations. Clicking on a TextView
item in this GridView
will open the application
to that category of tour location.
TourLocationContentProvider
: Maps URIs passed in from a ContentResolver
to actions
on the TourLocation
database - namely, SQL queries.
TourLocationContract
: Defines a URI for the database, which is needed by a ContentResolver
to interact with TourLocationContentProvider
. Also defines names for table columns.
TourLocationDbHelper
: Creates and updates the SQLite database as needed.
VolleyRequestQueue
: A singleton for a Volley
RequestQueue
(used for networking).
Used in URI queries in Utils/DirectionsIconClickListener
and Utils/InfoByIdsTask
.