CS5530 Mobile/Wireless Systems Using Google …yzhuang/CS5530/spring2017/slides/...Get a Google Maps...
Transcript of CS5530 Mobile/Wireless Systems Using Google …yzhuang/CS5530/spring2017/slides/...Get a Google Maps...
Ref.CN5E,NT@UW,WUSTLCS5530
CS5530Mobile/WirelessSystems
UsingGoogleMapinAndroid
YanyanZhuangDepartmentofComputerSciencehttp://www.cs.uccs.edu/~yzhuang
UC.ColoradoSprings
Setup
Ref.CN5E,NT@UW,WUSTL2CS5530
• InstalltheGooglePlayservicesSDKo Tools>Android>SDKmanager
CreateaGoogleMapsproject
Ref.CN5E,NT@UW,WUSTL3CS5530
• Select GoogleMapsActivity inthe'AddanactivitytoMobile'dialog
• Whenbuildfinished,AndroidStudioopensgoogle_maps_api.xml and MapsActivity.javao google_maps_api.xml containsinstructionsongettingaGoogleMaps
APIkeybeforeyoutrytoruntheapplication.
GetaGoogleMapsAPIkey
Ref.CN5E,NT@UW,WUSTL4CS5530
• AppsneedanAPIkeytoaccessGoogleMapsserverso Thekeyisfree.YoucanuseitwithanyofyourapplicationsthatcalltheGoogleMaps
AndroidAPI,anditsupportsanunlimitednumberofusers
1. Copythelinkin google_maps_api.xml, pasteitintobrowser2. FollowtheinstructionstocreateanewprojectontheGoogleAPI
Consoleorselectanexistingproject3. CreateanAndroid-restrictedAPIkeyforyourproject4. CopytheresultingAPIkey,gobacktoAndroidStudio,andpaste
theAPIkeyintothe<string>elementin google_maps_api.xmlMayusethesamekeyformorethanoneapp
Runtheapp
Ref.CN5E,NT@UW,WUSTL5CS5530
• Bydefault,theXMLfilethatdefinestheapp'slayoutisat res/layout/activity_maps.xml
• ThesimplestwaytoseeyourappinactionistoconnectanAndroiddevicetoyourcomputer
• YoucanuseAndroidEmulatortorunappo Whenchoosinganemulator,useAndroid4.2.2orhigher,andbecareful
topickanimagethatincludestheGoogleAPIs,ortheapplicationwillnothavetheruntimeAPIsinordertoexecute
Runtheapp(2)
Ref.CN5E,NT@UW,WUSTL6CS5530
• YoushouldseeamapwithamarkerpositionedoverSydney,Australiao Ifyoudon'tseeamap,checkthatyou'veaddedanAPIkeyasdescribed
o ChecktheloginAndroidStudio's AndroidMonitor forerrormessagesabouttheAPIkey
o DifferentwaystogettheAPIkeyhttps://developers.google.com/maps/documentation/android-api/signup
Understandthecode
Ref.CN5E,NT@UW,WUSTL7CS5530
• AndroidManifest.xmlo <meta-data
android:name="com.google.android.geo.API_KEY"android:value="@string/google_maps_key"/>(generatedforyou)
• activity_maps.xmlo <fragment> elementtoyouractivity'slayoutfile
o Definesa SupportMapFragment toactasacontainerforthemapandtoprovideaccesstothe GoogleMap object
<fragmentname="com.google.android.gms.maps.SupportMapFragment"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
Understandthecode
Ref.CN5E,NT@UW,WUSTL8CS5530
• Whatisafragment?o A Fragment representsabehaviororaportionofuserinterfacein
an Activity
o Cancombinemultiplefragmentsinasingleactivitytobuildamulti-paneUIandreuseafragmentinmultipleactivities
o Canthinkofafragmentasamodularsectionofanactivity,whichhasitsownlifecycle,receivesitsowninputevents,andwhichyoucanaddorremovewhiletheactivityisrunning} sortoflikea"subactivity"thatyoucanreuseindifferentactivities
Understandthecode
Ref.CN5E,NT@UW,WUSTL9CS5530
• MapsActivity’s onCreate()o @Override
protectedvoidonCreate(BundlesavedInstanceState){super.onCreate(savedInstanceState);//setthelayoutfileasthecontentviewsetContentView(R.layout.activity_maps);//getahandletothemapfragmentSupportMapFragment mapFragment =(SupportMapFragment)
getSupportFragmentManager().findFragmentById(R.id.map);//usegetMapAsync() toregisterformapcallback(whenmapisready)mapFragment.getMapAsync(this);
}
Understandthecode
Ref.CN5E,NT@UW,WUSTL10CS5530
• Implement OnMapReadyCallback interface&overrideonMapReady():setupthemapwhenGoogleMap objectisavailableo publicclassMapsActivity extendsAppCompatActivity
implementsOnMapReadyCallback {//OnCreate()methodhere:asdescribedonlastslide@OverridepublicvoidonMapReady(GoogleMap googleMap){//AddamarkerinSydney,Australia,andmovemap'scameraLatLng sydney =newLatLng(-33.852,151.211);googleMap.addMarker(newMarkerOptions().position(sydney)
.title("MarkerinSydney"));googleMap.moveCamera(CameraUpdateFactory.newLatLng(sydney));
}}
Understandthecode
Ref.CN5E,NT@UW,WUSTL11CS5530
• Bydefault,theGoogleMapsAPIdisplaysthecontentof“title”whentheusertapsamarkero googleMap.addMarker(newMarkerOptions().position(sydney)
.title("MarkerinSydney"));
• There'snoneedtoaddaclicklistenerforthemarkerifyou’rehappywiththedefaultbehavior
Summarize
Ref.CN5E,NT@UW,WUSTL12CS5530
• Thebasicstepsforaddingamap1. (Youonlyneedtodothisonce) GetGooglePlayServiceSDK,obtaina
keyandaddtherequiredattributestoAndroidmanifest
2. Adda <fragment> elementtothelayoutfileforthe Activity
3. Call getMapAsync() onthefragmenttoregisterthecallback
4. Implementthe OnMapReadyCallback interfaceandusethe onMapReady(GoogleMap)callbacktogetahandletothe GoogleMap object
MapTypes
Ref.CN5E,NT@UW,WUSTL13CS5530
• Normal• Hybrid• Terrain• Satellite• None
o GoogleMap map;...//Setsthemaptypetobe"hybrid"map.setMapType(GoogleMap.MAP_TYPE_HYBRID);
Markers
Ref.CN5E,NT@UW,WUSTL14CS5530
• Youcancustomizemarkersbychangingthedefaultcolor,orreplacingthemarkericonwithacustomimageo Infowindows canprovideadditionalcontexttoamarker
• Markersareobjectsoftype Markero AddedtomapwiththeGoogleMap.addMarker(markerOptions)method
o Receive click eventsbydefault,andareoftenusedwitheventlistenerstobringup infowindows
o Previousexample} googleMap.addMarker(newMarkerOptions().position(sydney).title("Markerin
Sydney"));
Markers
Ref.CN5E,NT@UW,WUSTL15CS5530
• Someotherexampleso Markermarker=googleMap.addMarker(new
MarkerOptions().position(newLatLng(-34,151)));
o marker.revmote();
o Settingamarkertobeinvisible,andtransparencyMarkermarker= googleMap.addMarker(new
MarkerOptions().position(newLatLng(-34,151)).visible(false).alpha(0.8f));
Markers
Ref.CN5E,NT@UW,WUSTL16CS5530
• Onceamarkeriscreated,youcanchangeitspropertyo marker.setAlpha(1.0f);
o marker.setVisible(true);
o marker.setPosition(newLatLng(-34,151));
• Whymarkervisibility?o Fastertomakeaninvisiblemarkervisible,thancreatinganewmarker
• Showinformationo googleMap.addMarker(new
MarkerOptions().position(sydney).title("Sydney").snippet(“Population:4.5millionin2015”));
Markers
Ref.CN5E,NT@UW,WUSTL17CS5530
• Respondtoclickeventso ActivitymustimplementGoogleMap.OnMarkerClickListener
o Setalistenerformarkerclick} @Override
publicvoidonMapReady(GoogleMap googleMap){…...mMap.setOnMarkerClickListener(this);
}
o ImplementcallbackfunctiononMarkerClick()
Markers
Ref.CN5E,NT@UW,WUSTL18CS5530
• Respondtoclickeventso ImplementcallbackfunctiononMarkerClick()
} @Overridepublicboolean onMarkerClick(finalMarkermarker){if(marker.equals(myMarker)){Toast.makeText(this,marker.getTitle()+"hasbeenclicked!",
Toast.LENGTH_LONG).show();}returnfalse;
}
Toasts
Ref.CN5E,NT@UW,WUSTL19CS5530
• Atoastprovidessimplefeedbackaboutanoperationinasmallpop-upo Onlyfillstheamountofspacerequiredforthemessageandthecurrent
activityremainsvisibleandinteractive
o Toastsautomaticallydisappearafteratimeout
• Instantiatea Toast objectwithmakeText()methodo 3parameters:theapplication Context(usuallythis),thetextmessage,
andthedurationforthetoast
o Toast.LENGTH_SHORT andToast.LENGTH_LONG
Toasts
Ref.CN5E,NT@UW,WUSTL20CS5530
• Exampleo Contextcontext=getApplicationContext();
CharSequence text="Hellotoast!";int duration=Toast.LENGTH_SHORT;
Toasttoast=Toast.makeText(context,text,duration);toast.show();
o Toast.makeText(context,text,duration).show();
Toasts
Ref.CN5E,NT@UW,WUSTL21CS5530
• PositioningyourToasto Astandardtoastnotificationappearsnearthebottomofthescreen,
centeredhorizontally
o Youcanchangethispositionwiththe setGravity(int,int,int) method:a Gravity constant,anx-positionoffset,anday-positionoffset
o Ifthetoastshouldappearinthetop-leftcorner} toast.setGravity(Gravity.TOP|Gravity.LEFT,0,0);
} Ifyouwanttonudgethepositiontotheright,increasethevalueofthesecondparameter.Tonudgeitdown,increasethevalueofthelastparameter
SelectCurrentPlace
Ref.CN5E,NT@UW,WUSTL22CS5530
• CreateaGoogleAPIcliento AlsoknownastheGoogleAPIclient:connectwithfusedlocation
providerandGooglePlacesAPI} privateGoogleApiClient mGoogleApiClient;
SelectCurrentPlace
Ref.CN5E,NT@UW,WUSTL23CS5530
• BuildaGoogleAPIcliento Requestthefusedlocationprovider(LocationServices.API)andthetwo
partsoftheGooglePlacesAPIforAndroid(Places.GEO_DATA_API andPlaces.PLACE_DETECTION_API)
o mGoogleApiClient =newGoogleApiClient.Builder(this).enableAutoManage(this/*FragmentActivity */,
this/*OnConnectionFailedListener */).addConnectionCallbacks(this).addApi(LocationServices.API).addApi(Places.GEO_DATA_API).addApi(Places.PLACE_DETECTION_API).build();
mGoogleApiClient.connect();
SelectCurrentPlace
Ref.CN5E,NT@UW,WUSTL24CS5530
• CannotresolveLocationServices andPlaces
• Adddependenciesinbuild.gradle (Module:app)o compile'com.google.android.gms:play-services-location:10.2.0'
compile'com.google.android.gms:play-services-places:10.2.0’
o Sync
o ThenwecanimportclassesforLocationServices andPlaces
SelectCurrentPlace
Ref.CN5E,NT@UW,WUSTL25CS5530
• CallbackfunctionsofmGoogleApiClient.connect()o @Override
publicvoidonConnected(BundleconnectionHint){...
}
/*HandlesfailuretoconnecttotheGooglePlayservicesclient.*/@OverridepublicvoidonConnectionFailed(@NonNull ConnectionResult result){Log.d(TAG,"Playservicesconnectionfailed:ConnectionResult.getErrorCode()="
+result.getErrorCode());}
/*HandlessuspensionoftheconnectiontotheGooglePlayservicesclient.*/@OverridepublicvoidonConnectionSuspended(int cause){Log.d(TAG,"Playservicesconnectionsuspended");
}
LocationServicesAPI
Ref.CN5E,NT@UW,WUSTL26CS5530
• Enablesordisablesthemy-locationlayero mMap.setMyLocationEnabled(true);
o Whileenabledandthelocationisavailable,themy-locationlayercontinuouslydrawsanindicationofauser'scurrentlocationandbearing,anddisplaysUIcontrolsthatallowausertointeractwiththeirlocation
o Inordertousethemy-location-layerfeatureyouneedtorequestpermissionforeitherACCESS_COARSE_LOCATIONorACCESS_FINE_LOCATION
LocationServicesAPI
Ref.CN5E,NT@UW,WUSTL27CS5530
• Enablesordisablesthemy-locationbuttono mMap.getUiSettings().setMyLocationButtonEnabled(true)
o Themy-locationbuttoncausesthecameratomovesuchthattheuser'slocationisinthecenterofthemap.Ifthebuttonisenabled,itisonlyshownwhenthemy-locationlayerisenabled
o Bydefault,themy-locationbuttonisenabled
LocationServicesAPI
Ref.CN5E,NT@UW,WUSTL28CS5530
• Getthebestandmostrecentlocationofthedevice(maybenullincaseswhenalocationisnotavailable)o mLastKnownLocation =LocationServices.FusedLocationApi
.getLastLocation(mGoogleApiClient);
• Setthemap'scamerapositiontothecurrentlocationofthedeviceandzoomino if(mLastKnownLocation !=null){
mMap.moveCamera(CameraUpdateFactory.newLatLngZoom(newLatLng(mLastKnownLocation.getLatitude(),
mLastKnownLocation.getLongitude()),DEFAULT_ZOOM));}
PlaceDetectionAPI
Ref.CN5E,NT@UW,WUSTL29CS5530
• Getanestimateoftheplacewherethedeviceiscurrentlylocatedo PendingResult<PlaceLikelihoodBuffer>result=Places.PlaceDetectionApi
.getCurrentPlace(mGoogleApiClient,null);
o GeneratesaPlaceLikelihoodBuffer basedondevice'slastestimatedlocation
o Returnedvaluesmaybeobtainedbymeansofanetworklookup:resultsareabestguessandnotguaranteedtobecorrect
o Requires ACCESS_FINE_LOCATION permission
o Accesstothismethodissubjecttoquotarestrictions
PlaceDetectionAPI
Ref.CN5E,NT@UW,WUSTL30CS5530
• Populateplaceinformationo result.setResultCallback(newResultCallback<PlaceLikelihoodBuffer>(){
@OverridepublicvoidonResult(@NonNull PlaceLikelihoodBuffer likelyPlaces){mLikelyPlaceNames =newString[mMaxEntries];…for(PlaceLikelihood placeLikelihood :likelyPlaces){//Buildalistoflikelyplacestoshowtheuser.Max5.mLikelyPlaceNames[i]=(String)placeLikelihood.getPlace().getName();…
}//Releasetheplacelikelihoodbuffer,toavoidmemoryleaks.likelyPlaces.release();
}});
SettinganAlertDialog forUserstoPick
Ref.CN5E,NT@UW,WUSTL31CS5530
• AlertDialog letsuserstointeractwiththeappo AlertDialog dialog=newAlertDialog.Builder(this)
.setTitle("pickaplace")
.setItems(mLikelyPlaceNames,listener)
.show();
o Syntax:useAlertDialog.Builder’s methodsetItems (CharSequence[]items,DialogInterface.OnClickListener listener)} Setalistofitemstobedisplayedinthedialogasthecontent
} Codewillbenotifiedoftheselecteditemviathesuppliedlistener
} Implementthelistener
SettinganAlertDialog forUserstoPick
Ref.CN5E,NT@UW,WUSTL32CS5530
• Listenero DialogInterface.OnClickListener listener=
newDialogInterface.OnClickListener(){@OverridepublicvoidonClick(DialogInterface dialog,int which){//The"which"argumentcontainsthepositionoftheselecteditem.LatLng markerLatLng =mLikelyPlaceLatLngs[which];StringmarkerSnippet =mLikelyPlaceAddresses[which];...//Addamarkerfortheselectedplace,withaninfowindoww/informationaboutthatplacemMap.addMarker(newMarkerOptions()
.title(mLikelyPlaceNames[which])
.position(markerLatLng)
.snippet(markerSnippet));
//Positionthemap'scameraatthelocationofthemarker.mMap.moveCamera(CameraUpdateFactory.newLatLngZoom(markerLatLng,
DEFAULT_ZOOM));}
};