se 390: software engineering for mobile devices week 12: geolocation copyright © steven w. johnson...

168
: Software Engineering for Mobile eek 12: Geolocation Copyright © Steven W. Johnson February 1, 2013

Upload: leonard-mccormick

Post on 17-Dec-2015

219 views

Category:

Documents


5 download

TRANSCRIPT

SE 390: Software Engineering for Mobile Devices

Week 12: GeolocationCopyright © Steven W. Johnson

February 1, 2013

GPS system

Geolocation

Google Maps

Lots of Trigonometry

Week 4:

2

Inspirational thought for the week:

3

Mobile devices are about portability

Portability is about knowing where you are

Mobile devices, geolocation are a natural fit

Geolocation starts with GPS

Movie project:

makes sense if device is aware of location

movie theatres within 50km of me

movies playing in my area

Primer on GPS:

4

Global Positioning System

Original: US military for navigation (Navstar)

Original implementation: 1973 (fixes TRANSIT)

Made available to public in 1983 (degraded system)

May 2000, selective availability removed

Other GPS systems: Russia, China, EU

Primer on GPS:

5

Primer on GPS:

6

*up to 31http://www.modern.nl/catalog/page.php?id=3751

24 satellites* in known positions

4 satellites in 6 different orbits

Theoretical: up to 8 satellites may see you

Orbits at 12,600 miles (20,200 km)

Low Earth Orbit (below 22,236 mi)

Primer on GPS:

7http://www.superbwallpapers.com

Space shuttle:

Orbits at 200 to 400 miles

15.9 orbits per day

Primer on GPS:

8http://www.kowoma.de/en/gps/orbits.htm

Six orbital paths:

orbit not geostationary

2 orbits a day

base orbit at 55°, others at ± 60°

View in blue

Primer on GPS:

9

Triangulation

Requires 4 satellites to place you in 3 dimensions

Distance from each satellite determines position

Consumer GPS: good to 10 meters

Satellite sends its time, device calculates distance

Device calculates its latitude and longitude

Primer on GPS:

10

349875124 349875133

349875131

349875128

349875139

156

11

8

Primer on GPS:

11

Latitude(ladder – merdiven)

Latitude (enlem)

Longitude (boylam)

Minutes

seconds

Longitude(boylam)

Primer on GPS:Our purposes today:

assume 1° of latitude, longitude are same

1° of latitude is constant everywhere

Turkey: longitude is 70% of latitude

Equator

45° N latitude

North Pole

24,900

17,600 or 70.5%

0

Primer on GPS:

13

Precision of degrees (derece) latitude:

1 degree69.16 miles 111.31 km

1 minute 1.15 miles 1.86 km

1 second 0.02 miles 0.03 km

GPS coordinates of Izmir:

Decimal: 34.422028° N, 27.129042° E

Sexagesimal:38° 24’ 26” N / 27° 09’ 01” E

Primer on GPS:

14

40,075.16 km to Earth’s circumference

1° of latitude (anywhere) = 111.3198 km

27.129042 deci

mete

rs

mete

rs

kilo

mete

rs

centi

mete

rs

11

1 k

ilom

ete

rs

Primer on GPS:

15

Distance: absolute difference between two points

Works well for short distances

.

.

Lat:Long:

34.422028 27.129042

34.448268 27.142674

Lat:Long:

dist x2

dist y2dist z

2

𝑧=√|𝑥2|+¿ 𝑦2∨¿¿

Primer on GPS:

16

.

.

Lat:Long:

34.422028 27.129042

34.448268 27.142674

Lat:Long:

dist x2

dist y2dist z

2

𝑧=√|𝑥2|+¿ 𝑦2∨¿¿Longitude

27.12904227.142674

-0.01363

2

0.013632

Latitude34.44826834.422028

0.026240

0.0262402

0.0136322

0.0006885376

0.0001858314

0.0008743690

𝑧=√0.00087436900.029569733.29km

Primer on GPS:

17

Shortest route on curved surface not ‘straight’

Great Circle Route

Primer on GPS:

18

Calculating the great circle route:

//radians = degrees * PI/180;

var R = 6371; // kmvar dLat = (lat2-lat1).toRad(); var dLon = (lon2-lon1).toRad(); var lat1 = lat1.toRad(); var lat2 = lat2.toRad(); var a = Math.sin(dLat/2) * Math.sin(dLat/2) + Math.sin(dLon/2) * Math.sin(dLon/2) * Math.cos(lat1) * Math.cos(lat2); var c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1-a)); var d = R * c;

GPS and Android:

19

How does a mobile device know its position?

1st alternative:

GPS (fine location)

2nd alternative:

use cell phone towers (coarse location)

3rd alternative:

use WiFi hotspot (desperation??)

GPS and Android:

20

GPS is a common feature in smartphones

Ubiquitous (her yerde birden bulunan) mobile devices

Organizations providing map data:

Google Maps

OpenStreetMap

Android Studio:

Google Map Template

GPS and Android:

21

Permissions must be turned on:

Internet

GPS

<uses-permissions> are children of <manifest>

<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.steve.johnson.gps" android:versionCode="1" android:versionName="1.0" > <uses-permission android:name="android.permission.INTERNET"/> <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" /> <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />

GPS and Andriod:

22

Two main elements:

location manager (web services)

location providers (technologies)

http://developer.android.com/reference/android/location/LocationManager.html

GPS and Andriod:

23http://developer.android.com/reference/android/location/LocationManager.html

Location loc = locationManager.getLastKnownLocation(provider); .getGpsStatus(GpsStatus status); .addProximityAlert(); .getBestProvider(Criteria criteria, boolean enabledOnly);

Location manager:

provides access to location services

determines current location

Some locationManager methods

Browsers have similar idea: ‘navigator’

Lab: GPS

24

Purpose: place a GPS location on emulator

Problem: emulator does not have GPS

Eclipse allowed for finer control than Studio

Studio works in decimal only*

Lab: GPS

25

Turn on Telnet:

Start

Control Panel

Programs

Turn Windows features on and off

Lab: GPS

26

Turn on Telnet:

CMD

telnet localhost 5554 (emulator port)

Lab: GPS

27

Opens Android console:

geo fix longitude latitude

Coordinates for IEU

geo fix 27.044622 38.388369

Lab: GPS

28

Turn on your emulator

Alternative methods:

Tools – Open Terminal

click ‘Terminal’ in lower left corner of IDE

Lab: GPS

29

Turn on your emulator

In the terminal:

Now told where emulator is located

Microsoft Windows [Version 6.1.7601]Copyright (c) 2009 Microsoft Corporation. All rights reserved.

C:\Users\Steve\Desktop\IMAX\app>

Microsoft Windows [Version 6.1.7601]Copyright (c) 2009 Microsoft Corporation. All rights reserved.

C:\Users\Steve\Desktop\IMAX\app>telnet localhost 5554

Microsoft Windows [Version 6.1.7601]Copyright (c) 2009 Microsoft Corporation. All rights reserved.

C:\Users\Steve\Desktop\IMAX\app>telnet localhost 5554

Android Console: type 'help' for a list of commandsOK

Microsoft Windows [Version 6.1.7601]Copyright (c) 2009 Microsoft Corporation. All rights reserved.

C:\Users\Steve\Desktop\IMAX\app>telnet localhost 5554

Android Console: type 'help' for a list of commandsOK geo fix 27.044622 38.388369OK

Lab: location

30

Create the project:

Lab: location

31

Get a key from ‘google_maps_api.xml’:<resources> <string name="google_maps_key_instructions" templateMergeStrategy="replace"> <!--

TODO: Before you run your application, you need a Google Maps API key.

To get one, follow this link, follow the directions and press "Create" at the end:

https://console.developers.google.com/flows/enableapi?apiid=maps_android_ backend&keyType=CLIENT_SIDE_ANDROID&r=74:76:97:C7:4F:25:91:43:6E:77:E1:FA :12:A1:5A:41:D5:A2:17:D0%3Bcom.example.sjohnson.location

You can also add your credentials to an existing key, using this line: 74:76:97:C7:4F:25:91:43:6E:77:E1:FA:12:A1:5A:41:D5:A2:17:D0;com.example .sjohnson.location

Once you have your key (it starts with "AIza"), replace the "google_maps_key" string in this file.-->

<resources> <string name="google_maps_key_instructions" templateMergeStrategy="replace"> <!--

TODO: Before you run your application, you need a Google Maps API key.

To get one, follow this link, follow the directions and press "Create" at the end:

https://console.developers.google.com/flows/enableapi?apiid=maps_android_ backend&keyType=CLIENT_SIDE_ANDROID&r=74:76:97:C7:4F:25:91:43:6E:77:E1:FA :12:A1:5A:41:D5:A2:17:D0%3Bcom.example.sjohnson.location

You can also add your credentials to an existing key, using this line: 74:76:97:C7:4F:25:91:43:6E:77:E1:FA:12:A1:5A:41:D5:A2:17:D0;com.example .sjohnson.location

Once you have your key (it starts with "AIza"), replace the "google_maps_key" string in this file.-->

Copy/paste into browser:

Lab: location

32

You’ll be required to login/create account:

Lab: location

33

34

35

Lab: location

36

Copy ‘API Key’ and paste into string for key

Can also place key in ‘strings’ and call in name

--> </string>

<string name="google_maps_key" templateMergeStrategy="preserve"> YOUR_KEY_HERE </string></resources>

--> </string>

<string name="google_maps_key" templateMergeStrategy="preserve"> AIzaSyBLAC9HJdk-kfI599kKGY7nRgR2Z0RVq8E </string></resources>

Lab: location

37

Manifest already has permissions built-in

package="com.example.steve.location" >

<uses-permission android:name="android.permission.INTERNET" /> <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" /> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> <uses-permission android:name="com.google.android.providers.gsf.permission.READ_GSERVICES" /><!-- The ACCESS_COARSE/FINE_LOCATION permissions are not required to use Google Maps Android API v2, but are recommended.--> <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" /> <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />

Lab: location

38

View map in emulator:

private void setUpMap() { mMap.addMarker(new MarkerOptions().position(new LatLng(0, 0)) .title("Marker"));}

Lab: location

39

Add coordinates and marker

‘setUpMap’ = define markers

Method at bottom of ‘Sourcecode’

private void setUpMap() { LatLng Izmir = new LatLng(38.4189, 27.1287); mMap.addMarker(new MarkerOptions() .position(Izmir) .title("Marker") );}

Lab: location

40

Coordinates added:

Lab: location

41

Add zoom to map:

generates map without marker

Method at bottom of ‘Sourcecode’

private void setUpMap() { LatLng Izmir = new LatLng(38.4189, 27.1287); mMap.moveCamera(CameraUpdateFactory.newLatLngZoom(Izmir, 15));}

Lab: location

42

Add zoom to map:

Lab: location

43

Zoom:

starts from 0: Earth fits in ≈256 dp

each size up doubles pixels required

1: 512 dp to show globe (10 cm)

2: 1,024 dp to show globe

3: 2,048 dp to show globe

Zoom method:

mMap.moveCamera(CameraUpdateFactory.newLatLngZoom(Izmir, 15));

Lab: location

44

Zoom:

Earth ‘0’ Earth ‘5’ Earth ‘10’ Earth ‘15’

Lab: locationChange MAP_TYPE_. Four alternatives:

terrain/normal (same appearance/look)

satellite

hybrid

none

Method at bottom of ‘Sourcecode’

private void setUpMap() { LatLng Izmir = new LatLng(38.4189, 27.1287); mMap.moveCamera(CameraUpdateFactory.newLatLngZoom(Izmir, 15)); mMap.setMapType(GoogleMap.MAP_TYPE_SATELLITE);

}

Lab: location

46

Map types:

SATELLITE TERRAIN /NORMAL

HYBRID NONE

Lab: location

47

Marker attributes:

private void setUpMap() { LatLng Izmir = new LatLng(38.4189, 27.1287); mMap.moveCamera(CameraUpdateFactory.newLatLngZoom(Izmir, 15)); mMap.setMapType(GoogleMap.MAP_TYPE_TERRAIN); mMap.addMarker(new MarkerOptions() .icon(BitmapDescriptorFactory.fromResource(R.drawable.turkeymarker)) .anchor(0.0f, 1.0f) // Anchors the marker on the bottom left .draggable(true) .alpha(0.5f) .rotation(90) .position(Izmir));

Lab: location

48

Marker attributes:

Lab: location

49

Customized marker:

.anchor(pos, pos)

(0.0, 0.0)

(0.0, 1.0)

(1.0, 0.0)

(1.0, 1.0)

Lab: location

50

Customized marker:

.anchor(pos, pos)

.anchor(.0425, 1)

Lab: location

51

Customized marker:

.draggable(true)

(long press to use)

Lab: location

52

Customized marker:

.alpha(0.0f to 1.0f)

Lab: location

53

Customized marker:

.rotation(0-360)

Lab: location

54

Adding ‘MyLocation’ layer of Google Map

Method at bottom of ‘Sourcecode’

private void setUpMap() { mMap.addMarker(new MarkerOptions().position(new LatLng(0, 0)).title("Marker"));}

private void setUpMap() { LatLng Izmir = new LatLng(38.4189, 27.1287); mMap.moveCamera(CameraUpdateFactory.newLatLngZoom(Izmir, 15)); mMap.setMyLocationEnabled(true); mMap.addMarker(new MarkerOptions() .icon(BitmapDescriptorFactory.fromResource(R.drawable.turkeymarker)) .position(Izmir));

Lab: location

55

‘MyLocation’

button (top right) centers map

location is:

blue dot (stationary)

chevrons (moving)

Lab: location

56

Locating yourself: (not in emulator; no GPS) 

private void setUpMap() { mMap.setMyLocationEnabled(true); LocationManager locationManager = (LocationManager) getSystemService(LOCATION_SERVICE); Criteria criteria = new Criteria(); String provider = locationManager.getBestProvider(criteria, true); Location location = locationManager.getLastKnownLocation(provider); double latitude = location.getLatitude(); double longitude = location.getLongitude(); LatLng MyHome = new LatLng(latitude, longitude); mMap.setMapType(GoogleMap.MAP_TYPE_TERRAIN); mMap.moveCamera(CameraUpdateFactory.newLatLngZoom(MyHome, 15));}

Lab: location

57

Locating yourself: (not in emulator; no GPS)

No icon defined (this example)

Lab: location

58

‘Sourcecode’:

much the same plus ‘setUpMap’ methods

private void setUpMapIfNeeded() { …builds the map setUpMap()}

private void setUpMap() { get location zoom display marker}

Lab: location

59

Two big ideas:

map what is being viewed

camera position/conditions of viewing

Move the camera or the map

Think of the camera as starting at (0, 0)

Lab: location

60

Camera position defines middle of map:

moveCamera place camera (no animation)

animateCamera place camera (with animation)

Lab: location

61

Camera position defines middle of map:

cameraUpdate

where and how camera moves

could be by lat/long or by pixels

changes an existing camera

cameraUpdateFactory “do the cameraUpdate”

Lab: location

62

Important commands:

setTrafficEnabled(true);

Lab: location

63

This method:

private void setUpMap() { LatLng Izmir = new LatLng(38.4189, 27.1287); mMap.moveCamera(CameraUpdateFactory.newLatLngZoom(Izmir, 15)); mMap.setMapType(GoogleMap.MAP_TYPE_TERRAIN); mMap.addMarker(new MarkerOptions() .icon(BitmapDescriptorFactory.fromResource(R.drawable.turkeymarker)) .anchor(0.0f, 1.0f) // Anchors the marker on the bottom left .draggable(true) .alpha(0.5f) .rotation(90) .position(Izmir));

Break 64

Images in Android

65

A test:

created an image of 350 x 130 @ 72ppi

copied using each resolution of ‘drawable’

added each image to a layout

Images in Android

66

Results:‘drawable’

‘ldpi’

‘mdpi’

‘hdpi’

‘xhdpi’

‘xxhdpi’

450px

450px

600px

150px

225px

300px

Images in Android

67

Considerations:

desktop monitors render at 96ppi

default Photoshop setting is 72ppi

Bucket Size Pixels per 160dp

Launcher Icon size

Renders like

Impact toDesktop

‘drawable’ 96ppi 0

ldpi 120 36x36 72ppi +33%

mdpi 160 48x48 96ppi 0

hdpi 240 72x72 144ppi -33%

xhdpi 320 96x96 192ppi -50%

xxhdpi 480 144x144 288ppi -67%

Android L: Android Lollipop (API 21)

Covers versions 5.0 and 5.1

Biggest change: material design

Dalvik replaced by ART (Android RunTime)

Two new widgets:

RecyclerView

CardView

RecyclerView and CardView

68http://www.itpro.co.uk/mobile/22562/android-lollipop-release-date-specs

RecyclerView and CardView

69

CardView:

a container that holds images, text

a repeated element; a <li>

RecyclerView:

container that holds cards

like a <ul>

Both are new with Lollipop (API 21)

Support down to API 7 with libraries

RecyclerView and CardView

70

RecyclerView

CardView

CardView

Title ADataDataData

Title BDataDataData

Normal list:

This lab:

RecyclerView and CardView

71

control adapter array

recycler

adapter

cardView

Lab: Area Cinemas

72

To complete:

list all theatres within 50 km of ‘your location’

connect to MySQL database (imaxdb)

read out latitude and longitude

compare to IEU latitude/longitude:

longitude: 27.044622

latitude: 38.388369

1° of difference = 111.3198 km

sort by distance ascending (yükselen)http://code.tutsplus.com/tutorials/getting-started-with-recyclerview-and-cardview-on-android--cms-23465

Lab: Area Cinemas

73

Output of the app:

http://code.tutsplus.com/tutorials/getting-started-with-recyclerview-and-cardview-on-android--cms-23465

Lab: Area Cinemas

74

Lab uses two full activities and two helper classes

StructurecodeAdaptercodeCardcodeRecyclercode

recyclerlayout cardlayout

http://code.tutsplus.com/tutorials/getting-started-with-recyclerview-and-cardview-on-android--cms-23465

Lab: Area Cinemas

75

Turn on your web server

Open your ‘www’ folder

Add ‘getCinemaList.php’ (in-class files)

Lab: Area Cinemas

76

Create the web service:

send current coordinates to web service

use coordinates of theaters in DB

criteria:

distance (km) = 111.3198 *

distance <=50

sort ascending (yükselen)

name of file: getCinemaList.php

Lab: Area Cinemas

77

Connect to the database

Capture location of device<?php $host = "localhost"; $username = "your_user"; $password = "your_pass"; $database = "imaxdb"; $con = mysqli_connect($host, $username, $password, $database) or trigger_error(mysqli_error(),E_USER_ERROR);

$latPosition = mysqli_real_escape_string($con, $_GET['latitude']); $longPosition= mysqli_real_escape_string($con, $_GET['longitude']);

$query = "SELECT theatrename, latitude, longitude, theatrepix, streetaddress, citystatezip FROM theatres"; $recordset = mysqli_query($con, $query); $count = mysqli_num_rows($recordset);

Lab: Area Cinemas

78

Recordset holds every theatre in world

SELECT ‘regional’ movie theatres<?php $host = "localhost"; $username = "your_user"; $password = "your_pass"; $database = "imaxdb"; $con = mysqli_connect($host, $username, $password, $database) or trigger_error(mysqli_error(),E_USER_ERROR);

$latPosition = mysqli_real_escape_string($con, $_GET['latitude']); $longPosition= mysqli_real_escape_string($con, $_GET['longitude']);

$query = "SELECT theatrename, latitude, longitude, theatrepix, streetaddress, citystatezip FROM WHERE lat and long within ½° of current location; $recordset = mysqli_query($con, $query); $count = mysqli_num_rows($recordset);

Lab: Area Cinemas

79

.current location

½° = 55.5km ½° = 55.5km

½° = 55.5km

½° = 55.5km70km

Lab: Area Cinemas

80

Refine the list to within 50km:

for ($i=0; $i<$count; $i++) { $row=mysqli_fetch_assoc($recordset); $latDistance = abs($row['latitude'] - $latPosition); $longDistance = abs($row['longitude'] - $longPosition); $latSquare = pow($latDistance, 2); $longSquare = pow($longDistance, 2); $Distance = 111.3198 * sqrt($latSquare + $longSquare); $Distance = number_format($Distance, 1); if ($Distance <= 50) {

$data = array("theatrename" => $row['theatrename'], "theatrepix" =>$row['theatrepix'], "streetaddress" => $row['streetaddress'], "citystatezip" => $row['citystatezip'], "distance" => $Distance." km");

$output[] = $data; }}

Lab: Area Cinemas

81

Order the cinemas by distance from device

Send final output back to the devicefunction cust_sort($a,$b) { return strtolower($a[distance]) > strtolower($b[distance]);}usort($output, 'cust_sort');mysqli_free_result($row);mysqli_close($con);echo json_encode($output, JSON_UNESCAPED_UNICODE);?>

Lab: Area Cinemas

82

Test ‘getCinemaList’ in browser

Should get 4 returns (Foça, Ceşme too far away)

http://localhost/getCinemaList.php?latitude=38.388369&longitude=27.044622

Lab: Area Cinemas

83

Create a project: (use API 21 for elevation)

Lab: Area Cinemas

84

Recent upgrade included API 22

Potential rendering problems with ‘Design View’

Solution:

change API from 22 to 21

put back to 22 if you want

Lab: CinemaList

86

Create ‘cardview’ activity

rt. click: ‘layout’ – New – Activity – Blank Activity

Lab: CinemaList

87

Create a class for the Recycler adapter

Open ‘Java’ – rt. Click on Package (NOT –TEST)

New – Java Class

Lab: CinemaList

88

Create second class for the Card’s content

Open ‘Java’ – rt. Click on Package (NOT –TEST)

New – Java Class

Lab: CinemaList

89

Add the icon: Rt click ‘res’ – New – Image Asset

90

Update ‘build.gradle (Module: app)’:

Add bottom two ‘compiles’

Sync the project

‘+’ on end is not good, but not horrible either

means ‘get most current’

dependencies { compile fileTree(dir: 'libs', include: ['*.jar']) compile 'com.android.support:recyclerview-v7:21.0.+' compile 'com.android.support:cardview-v7:21.0.+'}

Lab: Area Cinemas

91

Update ‘AndroidManifest’:

Permissions to use the Internet

<?xml version="1.0" encoding="utf-8"?><manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.example.sjohnson.areacinemas" > <uses-permission android:name="android.permission.INTERNET" /> <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />

Lab: Area Cinemas

<activity android:name="com.example.steve.areacinemas.Cardcode" android:label="app_name" > </activity>

92

Update ‘strings’:

Lab: Area Cinemas

<resources> <string name="app_name">Area Cinemas</string> <string name="altText">Image of Theatre Marquee</string></resources>

93

Update ‘dimens’:

Lab: Area Cinemas

<resources> <!-- Default screen margins--> <dimen name="dp16">16dp</dimen> <dimen name="dp8">8dp</dimen> <dimen name="dp5">5dp</dimen> <dimen name="sp16">16sp</dimen> <dimen name="sp12">12sp</dimen></resources>

94

Create ‘colors.xml’:

Lab: Area Cinemas

<?xml version="1.0" encoding="utf-8"?><resources>

<color name="cardcolor">#ffefe8da</color> <color name="recyclercolor">#fff1f8ff</color>

</resources>

95

Copy 6 ‘city cinema’ images

Paste into ‘drawable’

Lab: Area Cinemas

96

Open ‘recyclerlayout’: (the RecyclerView)

delete ‘hello world’

change ‘RelativeLayout’ to ‘LinearLayout’

update ‘LinearLayout’:

layout_width & height: match_parent

background: @color/recyclercolor’

padding (all): ‘@dimen/dp8’

Lab: Area Cinemas

97

Add a ‘CustomView’

Click on ‘Custom’ and search of ‘RecyclerView’

Select and ‘OK’

Click on ‘LinearLayout’ to add

Lab: Area Cinemas

98

Open ‘recyclerlayout’: (the RecyclerView)

get a rendering error

can’t be previewed in ‘design’ window

potential fixes: not worth it

Lab: Area Cinemas

99

Update the ‘RecyclerView’

Copy/paste this code in place of ‘view’

Done with ‘recyclerlayout’

<android.support.v7.widget.RecyclerView android:layout_width="match_parent" android:layout_height="match_parent“ android:id="@+id/recycler" />

Lab: Area Cinemas

100

cardlayout holds the CardView

Describes one instance of a card

CardView: like rubber stamp

Recycler: the repeater

Data fed into CardView using Adapter (like list)

Lab: Area Cinemas

RecyclerView

CardView

CardView

CardView

101

Open ‘cardlayout’: (the CardView)

delete ‘hello world’

change to ‘LinearLayout’

Lab: Area Cinemas

102

Update the ‘LinearLayout’:

layout_width: match_parent

layout_height: wrap_content

orientation: vertical

background: ‘@color/cardcolor’

elevation: ‘dimen/dp5’

padding (all): ‘@dimen/dp8’

Lab: Area Cinemas

103

Add ‘CardView’

Click ‘OK’ and add to LinearLayout

Lab: Area Cinemas

104

Update the CardView on

‘listing.xml’

copy/paste above

‘LinearLayout’

And below </LinearLayout>:

Lab: Area Cinemas

<?xml version="1.0" encoding="utf-8"?> <android.support.v7.widget.CardView xmlns:android="http://schemas.android.com/apk/res/android" xmlns:card_view="http://schemas.android.com/apk/res-auto" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginBottom="@dimen/dp8" card_view:cardCornerRadius="@dimen/dp8" android:id="@+id/cardview" >

</android.support.v7.widget.CardView>

105

Current ‘cardlayout’

Lab: Area Cinemas

<?xml version="1.0" encoding="utf-8"?> <android.support.v7.widget.CardView xmlns:android="http://schemas.android.com/apk/res/android" xmlns:card_view="http://schemas.android.com/apk/res-auto" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginBottom="@dimen/dp8" card_view:cardCornerRadius="@dimen/dp8" android:id="@+id/cardview" > <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" tools:context="com.example.steve.areacinemas.Cardcode" android:orientation="vertical" android:background="@color/cardcolor" android:elevation="@dimen/dp5" android:padding="@dimen/dp8"> </LinearLayout> </android.support.v7.widget.CardView>

106

Update the ‘LinearLayout’

add an ImageView

add three TextViews

Lab: Area Cinemas

107

Update the ‘ImageView’

layout_width: match_parent

layout_height: wrap_content

contentDescription: ‘@string/altText’

id: theatrePix

scaleType: fitStart

src: (none)

Lab: Area Cinemas

108

Update 1st TextView:

id: theatreName

text: (none)

textSize: ‘@dimen/sp16’

Lab: Area Cinemas

109

Update 2nd TextView:

id: theatreAddress

text: (none)

textSize: ‘@dimen/sp12’

Lab: Area Cinemas

110

Update 3rd TextView:

id: theatreCity

text: (none)

textSize: ‘@dimen/sp12’

Lab: Area Cinemas

111

Update 4th TextView:

id: distance

text: (none)

textSize: ‘@dimen/sp12’

Lab: Area Cinemas

112

Update ‘Recyclercode’

calls the recycler (which calls the cards)

connects to web service

translates transmitted data

feeds the adapter

Delete ‘OptionsMenu’ and ‘ItemSelected’ menu

Lab: Area Cinemas

113

Update ‘Recyclercode’ (red currently undefined)public class Recyclercode extends Activity {

private List<Theatre> movieHouses; private RecyclerView recycler;

@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.recyclerlayout);

recycler=(RecyclerView)findViewById(R.id.recycler);

LinearLayoutManager llm = new LinearLayoutManager(this); recycler.setLayoutManager(llm); recycler.setHasFixedSize(true);

initializeData(); initializeAdapter(); }

Lab: Area Cinemas

114

Update ‘Recyclercode’ (connect to web service)

private void initializeData(){ movieHouses = new ArrayList<>();

if (android.os.Build.VERSION.SDK_INT > 9) { StrictMode.ThreadPolicy policy = new StrictMode.ThreadPolicy.Builder().permitAll().build(); StrictMode.setThreadPolicy(policy); }

String latitude = "38.5"; String longitude = "27.0";

String url = "http://10.0.2.2/getCinemaList.php?latitude= +latitude+"&longitude="+longitude;

Lab: Area Cinemas

115

Update ‘Recyclercode’ (extract data from service)

try { JSONArray data = new JSONArray(getJSONUrl(url)); int arrSize = data.length(); String a, b, c, d, e; //done to save vertical space

for (int i = 0; i < arrSize; i++) { JSONObject blob = data.getJSONObject(i); a = blob.getString("theatrename"); b = blob.getString("streetaddress"); c = blob.getString("theatrepix"); d = blob.getString("citystatezip"); e = blob.getString("distance"); int pixID = getResources().getIdentifier(c, "drawable", getPackageName()); movieHouses.add(new Theatre(a, b, pixID, d, e)); }} catch (JSONException e) { e.printStackTrace();}}

Lab: Area Cinemas

116

Update ‘Recyclercode’ (extract data from service)

private void initializeAdapter(){ Adaptercode adapter = new Adaptercode(movieHouses); recycler.setAdapter(adapter);}

Lab: Area Cinemas

117

Update ‘Recyclercode’ (extract data from service)

public String getJSONUrl(String url) { StringBuilder str = new StringBuilder(); HttpClient client = new DefaultHttpClient(); HttpGet httpGet = new HttpGet(url); try { HttpResponse response = client.execute(httpGet); StatusLine statusLine = response.getStatusLine(); int statusCode = statusLine.getStatusCode(); if (statusCode == 200) { HttpEntity entity = response.getEntity(); InputStream content = entity.getContent(); BufferedReader reader = new BufferedReader(new InputStreamReader(content)); String line; while ((line = reader.readLine()) != null) { str.append(line); } } else { Log.e("Log", "Failed to download result.."); } } catch (IOException e) { e.printStackTrace(); } return str.toString();}

Lab: Area Cinemas

118

Update ‘Cardcode’: Defines views used in card

Lab: Area Cinemas

public class Cardcode extends Activity {

TextView theatreName; TextView theatreAddress; ImageView theatrePix; TextView theatreCity; TextView theatreDistance;

@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.cardlayout);

theatreName = (TextView)findViewById(R.id.theatreName); theatreAddress = (TextView)findViewById(R.id.theatreAddress); theatrePix = (ImageView)findViewById(R.id.theatrePix); theatreCity = (TextView)findViewById(R.id.theatreCity); theatreDistance = (TextView)findViewById(R.id.distance);

}}

119

Update ‘Structurecode’: defines list ‘Theatre’

Lab: Area Cinemas

class Theatre { String name; String address; int pix; String city; String distance;

Theatre(String name, String address, int pix, String city, String distance) { this.name = name; this.address = address; this.pix = pix; this.city = city; this.distance = distance; }}

120

Update ‘Adaptercode’:

Lab: Area Cinemas

public class Adaptercode extends RecyclerView.Adapter<Adaptercode.PersonViewHolder> {

public static class PersonViewHolder extends RecyclerView.ViewHolder {

CardView cardview; TextView theatreName; TextView theatreAddress; ImageView theatrePix; TextView theatreCity; TextView theatreDistance;

PersonViewHolder(View itemView) { super(itemView); cardview = (CardView)itemView.findViewById(R.id.cardview); theatreName = (TextView)itemView.findViewById(R.id.theatreName); theatreAddress = (TextView)itemView.findViewById(R.id.theatreAddress); theatrePix = (ImageView)itemView.findViewById(R.id.theatrePix); theatreCity = (TextView)itemView.findViewById(R.id.theatreCity); theatreDistance = (TextView)itemView.findViewById(R.id.distance); } }

121

Update ‘Adaptercode’:

Lab: Area Cinemas

List<Theatre> movieHouses; Adaptercode(List<Theatre> movieHouses){ this.movieHouses = movieHouses; }

@Override public void onAttachedToRecyclerView(RecyclerView recyclerView) { super.onAttachedToRecyclerView(recyclerView); }

@Override public PersonViewHolder onCreateViewHolder(ViewGroup viewGroup, int i) { View v = LayoutInflater.from(viewGroup.getContext()).inflate (R.layout.cardlayout, viewGroup, false); PersonViewHolder pvh = new PersonViewHolder(v); return pvh; }

122

Update ‘Adaptercode’:

Lab: Area Cinemas

@Override public void onBindViewHolder(PersonViewHolder personViewHolder, int i) { personViewHolder.theatreName.setText(movieHouses.get(i).name); personViewHolder.theatreAddress.setText(movieHouses.get(i).address); personViewHolder.theatrePix.setImageResource(movieHouses.get(i).pix); personViewHolder.theatreCity.setText(movieHouses.get(i).city); personViewHolder.theatreDistance.setText(movieHouses.get(i).distance); }

@Override public int getItemCount() { return movieHouses.size(); }}

123

Done!

listing based on location

image size based on drawable

hdpi appearance

Lab: Area Cinemas

1. How many satellites does it take to position you on Earth?

A. 1B. 2C. 3D. 4E. At least 6F. At least 8

Quiz:

124

2. What type of orbit are GPS satellites in?

A. Low Earth OrbitB. High Earth OrbitC. Geostationary OrbitD. Parabolic OrbitE. Circular Orbit

Quiz:

125

3. The precision of the civilian GPS system is to the nearest:

A. 1 centimeterB. 1 meterC. 10 metersD. 100 meters

Quiz:

126

4. One degree of latitude (at equator) is how many kilometers?

A. 1 kmB. 10 kmC. 100 kmD. 1,000 km

Quiz:

127

5. A latitude of 15 degrees and a longitude of 40 degrees is on which continent?

A. AsiaB. AfricaC. EuropeD. North AmericaE. South AmericaF. AustraliaG. Antarctica

Quiz:

128

6. “Fine location” uses:

A. GPSB. Cell phone towersC. Wi-fi hotspots

Quiz:

129

7. “Coarse location” uses:

A. GPSB. Cell phone towersC. Wi-fi hotspots

Quiz:

130

SE 390: Software Engineering for Mobile Devices

Week 12: GeolocationCopyright © Steven W. Johnson

February 1, 2013

Lab: Every Theatre

132

Next trick: show all cinemas on the map

Place all the cinemas on the map

Use ‘placeCinemas.php’ web service (very similar)

Use one activity

Lab: Every Theatre

133

Theatre name

Get/test coordinates

Calculate distance

‘placeMarkers.php’ (in-class files)

turn on web server

copy ‘placeMarkers.php’ to web server

Lab: Every Theatre

134

Lab: Every Theatre

135

<?php $host = "localhost"; $username = "your_user"; $password = "your-pass"; $database = "imaxdb"; $con = mysqli_connect($host, $username, $password, $database) or trigger_error(mysqli_error(),E_USER_ERROR);

$latPosition = mysqli_real_escape_string($con, $_GET['latitude']); $longPosition= mysqli_real_escape_string($con, $_GET['longitude']);

$query = "SELECT theatrename, latitude, longitude, theatrepix FROM theatres"; $recordset = mysqli_query($con, $query); $count = mysqli_num_rows($recordset);

for ($i=0; $i<$count; $i++) { $row=mysqli_fetch_assoc($recordset); $latDistance = abs($row['latitude'] - $latPosition); $longDistance = abs($row['longitude'] - $longPosition); $latSquare = pow($latDistance, 2); $longSquare = pow($longDistance, 2); $Distance = 111.3198 * sqrt($latSquare + $longSquare); $Distance = number_format($Distance, 1); if ($Distance <= 50) { $data = array("theatrename" => $row['theatrename'], "latitude" => $row['latitude'], "longitude" => $row['longitude'], "distance" => $Distance. " km"); $output[] = $data; } } mysqli_free_result($row); mysqli_close($con); echo json_encode($output, JSON_UNESCAPED_UNICODE);?>

Create the project:

Lab: Every Theatre

136

Add the icon:

Lab: Every Theatre

137

Lab: Every Theatre

138

Get a key from ‘google_maps_api.xml’:<resources> <string name="google_maps_key_instructions" templateMergeStrategy="replace"> <!--

TODO: Before you run your application, you need a Google Maps API key.

To get one, follow this link, follow the directions and press "Create" at the end:

https://console.developers.google.com/flows/enableapi?apiid=maps_android_ backend&keyType=CLIENT_SIDE_ANDROID&r=74:76:97:C7:4F:25:91:43:6E:77:E1:FA :12:A1:5A:41:D5:A2:17:D0%3Bcom.example.sjohnson.location

You can also add your credentials to an existing key, using this line: 74:76:97:C7:4F:25:91:43:6E:77:E1:FA:12:A1:5A:41:D5:A2:17:D0;com.example .sjohnson.location

Once you have your key (it starts with "AIza"), replace the "google_maps_key" string in this file.-->

<resources> <string name="google_maps_key_instructions" templateMergeStrategy="replace"> <!--

TODO: Before you run your application, you need a Google Maps API key.

To get one, follow this link, follow the directions and press "Create" at the end:

https://console.developers.google.com/flows/enableapi?apiid=maps_android_ backend&keyType=CLIENT_SIDE_ANDROID&r=74:76:97:C7:4F:25:91:43:6E:77:E1:FA :12:A1:5A:41:D5:A2:17:D0%3Bcom.example.sjohnson.location

You can also add your credentials to an existing key, using this line: 74:76:97:C7:4F:25:91:43:6E:77:E1:FA:12:A1:5A:41:D5:A2:17:D0;com.example .sjohnson.location

Once you have your key (it starts with "AIza"), replace the "google_maps_key" string in this file.-->

Copy/paste into browser:

Lab: Every Theatre

139

You’ll be required to login/create account:

Lab: Every Theatre

140

141

142

Add your API key

Lab: Every Theatre

143

Add ‘drawable’ markers:

location (red)

mylocation (orange)

copy image and paste into ‘drawable’

Lab: Every Theatre

144

Determine present location (mobile)

Add IEU location (emulator)

Lab: Every Theatre

145

private void setUpMap() { double latitude = 0.0d; double longitude = 0.0d; mMap.setMyLocationEnabled(true); LocationManager locationManager = (LocationManager)getSystemService(LOCATION_SERVICE); Criteria criteria = new Criteria(); String provider = locationManager.getBestProvider(criteria, true); Location location = locationManager.getLastKnownLocation(provider);

if (location == null) { latitude = 38.388369; longitude = 27.044622; } else { latitude = location.getLatitude(); longitude = location.getLongitude(); }

Determine present location (mobile)

Add IEU location (emulator)

Lab: Every Theatre

146

LatLng position = new LatLng(latitude, longitude);mMap.moveCamera(CameraUpdateFactory.newLatLngZoom(position, 11));mMap.addMarker(new MarkerOptions() .icon(BitmapDescriptorFactory.fromResource(R.drawable.mylocation)) .title("My Location") .snippet("Lat: " + latitude + " Long: " + longitude) .position(position));}

Get the locations of the cinemas

Process:

read next theater out of array

place marker on screen

no need for array or list

Lab: Every Theatre

147

Connect to the web service:

Lab: Every Theatre

148

if (android.os.Build.VERSION.SDK_INT > 9) { StrictMode.ThreadPolicy policy = newStrictMode.ThreadPolicy.Builder() .permitAll().build(); StrictMode.setThreadPolicy(policy);}

String url = "http://10.0.2.2/placeMarkers.php?latitude=" +latitude+ "&longitude=" +longitude;

Lab: Every Theatre

149

try { JSONArray data = new JSONArray(getJSONUrl(url)); int arrSize = data.length(); String a, b, c, d; for (int i = 0; i < arrSize; i++) { JSONObject blob = data.getJSONObject(i); a = blob.getString("theatrename"); b = blob.getString("latitude"); c = blob.getString("longitude"); d = blob.getString("distance"); double readlat = Double.parseDouble(b); double readlong = Double.parseDouble(c); LatLng pos = new LatLng(readlat, readlong); mMap.addMarker(new MarkerOptions() .icon(BitmapDescriptorFactory .fromResource(R.drawable.location)) .title(a) .snippet(d) .position(pos)); }} catch (JSONException e) { e.printStackTrace();}}

Lab: Every Theatre

150

public String getJSONUrl(String url) { StringBuilder str = new StringBuilder(); HttpClient client = new DefaultHttpClient(); HttpGet httpGet = new HttpGet(url); try { HttpResponse response = client.execute(httpGet); StatusLine statusLine = response.getStatusLine(); int statusCode = statusLine.getStatusCode(); if (statusCode == 200) { HttpEntity entity = response.getEntity(); InputStream content = entity.getContent(); BufferedReader reader = new BufferedReader(new InputStreamReader(content)); String line; while ((line = reader.readLine()) != null) { str.append(line); } } else { Log.e("Log", "Failed to download result.."); } } catch (IOException e) { e.printStackTrace(); } return str.toString();}

HttpClient class deprecated as of API 22

Can ‘fix’ deprecated problem by compiling in 21

Lab: Every Theatre

151http://developer.android.com/reference/android/net/http/AndroidHttpClient.html

Done! (all are shown this image)

Lab: Every Theatre

152

Break 153

Lab starts from IEU or your location

Click on map and get coordinates of location

To complete:

have the ‘normal’ addMarker method

add ‘onClickListener’

clear old ‘addMarker’

add new ‘addMarker’

Lab: My Location

154http://developer.android.com/reference/android/net/http/AndroidHttpClient.html

Create the project:

Lab: My Location

155

Lab: My Location

156

Get a key from ‘google_maps_api.xml’:<resources> <string name="google_maps_key_instructions" templateMergeStrategy="replace"> <!--

TODO: Before you run your application, you need a Google Maps API key.

To get one, follow this link, follow the directions and press "Create" at the end:

https://console.developers.google.com/flows/enableapi?apiid=maps_android_ backend&keyType=CLIENT_SIDE_ANDROID&r=74:76:97:C7:4F:25:91:43:6E:77:E1:FA :12:A1:5A:41:D5:A2:17:D0%3Bcom.example.sjohnson.location

You can also add your credentials to an existing key, using this line: 74:76:97:C7:4F:25:91:43:6E:77:E1:FA:12:A1:5A:41:D5:A2:17:D0;com.example .sjohnson.location

Once you have your key (it starts with "AIza"), replace the "google_maps_key" string in this file.-->

<resources> <string name="google_maps_key_instructions" templateMergeStrategy="replace"> <!--

TODO: Before you run your application, you need a Google Maps API key.

To get one, follow this link, follow the directions and press "Create" at the end:

https://console.developers.google.com/flows/enableapi?apiid=maps_android_ backend&keyType=CLIENT_SIDE_ANDROID&r=74:76:97:C7:4F:25:91:43:6E:77:E1:FA :12:A1:5A:41:D5:A2:17:D0%3Bcom.example.sjohnson.location

You can also add your credentials to an existing key, using this line: 74:76:97:C7:4F:25:91:43:6E:77:E1:FA:12:A1:5A:41:D5:A2:17:D0;com.example .sjohnson.location

Once you have your key (it starts with "AIza"), replace the "google_maps_key" string in this file.-->

Copy/paste into browser:

Lab: My Location

157

You’ll be required to login/create account:

Lab: My Location

158

159

160

Add your API key

Lab: My Location

161

Add a drawable ‘location.png’

Copy/paste ‘location.png’ into ‘drawable’ folder

Lab: My Location

162

Open ‘Sourcecode’: (setUpMap)

Lab: My Location

163

private void setUpMap() { double latitude = 0.0; double longitude = 0.0; mMap.setMyLocationEnabled(true); LocationManager locationManager = (LocationManager)getSystemService(LOCATION_SERVICE); Criteria criteria = new Criteria(); String provider = locationManager.getBestProvider(criteria, true); Location location = locationManager.getLastKnownLocation(provider);

if (location == null) { latitude = 38.388369; longitude = 27.044622; } else { latitude = location.getLatitude(); longitude = location.getLongitude(); }

Open ‘Sourcecode’: (setUpMap)

Lab: My Location

164

LatLng position = new LatLng(latitude, longitude); mMap.moveCamera(CameraUpdateFactory.newLatLngZoom(position, 11)); mMap.addMarker(new MarkerOptions() .icon(BitmapDescriptorFactory .fromResource(R.drawable.location)) .title("My Location") .snippet("Lat: " + latitude + " Long: " + longitude) .position(position));

Open ‘Sourcecode’: (onClickListener)

Lab: My Location

mMap.setOnMapClickListener(new GoogleMap.OnMapClickListener() {

@Override public void onMapClick(LatLng latLng) { MarkerOptions markerOptions = new MarkerOptions(); markerOptions.position(latLng); double a = latLng.latitude; double newLat = (double) Math.round(a*1000000)/1000000; double b = latLng.longitude; double newLong = (double) Math.round(b*1000000)/1000000; markerOptions.title("This location"); markerOptions.snippet("Lat: " +newLat+ " Long: "+newLong); markerOptions.icon(BitmapDescriptorFactory .fromResource(R.drawable.location));

mMap.clear(); mMap.animateCamera(CameraUpdateFactory.newLatLng(latLng)); mMap.addMarker(markerOptions); }});

1. 2. 3.

Done!

Lab: My Location

166

Geolocate five locations with these businesses

Map must show all five locations

Make database to define location, type, etc.

Make a marker for each type of business

2 fast food restaurants

two ATMs

1 mall

use your name as the snippet on each one

Assignment: Businesses

167

SE 390: Software Engineering for Mobile Devices

Week 12: GeolocationCopyright © Steven W. Johnson

February 1, 2013