05 ExternalServices

Download as pptx, pdf, or txt
Download as pptx, pdf, or txt
You are on page 1of 25

External Services

CSE 5236: Mobile Application Development


Course Coordinator: Dr. Rajiv Ramnath
Instructor: Dr. Adam C. Champion
Reading: Big Nerd Ranch Guide, Chap. 30 (WebView);
Chaps. 33, 34 (Google Play services, maps)

1
External Services
• Viewing websites
• Location- and map-based functionality
• REST-based Web services invocation

2
Invoking Browser App
Java Kotlin
// HelpFragment.java // HelpFragment.kt
private void launchBrowser( private fun launchBrowser(
String url) { url: String) {
Uri theUri = Uri.parse(url); val theUri = Uri.parse(url)
Intent LaunchBrowserIntent = val LaunchBrowserIntent =
new Intent(Intent.ACTION_VIEW, Intent(Intent.ACTION_VIEW,
theUri); theUri)
startActivity( startActivity(
LaunchBrowserIntent); LaunchBrowserIntent)
} }

URL: http://en.wikipedia.org/wiki/Tictactoe
3
Note: Activity stacking due to re-launch of browser on mobile page
Embedded WebView - Layout
<?xml version="1.0" encoding="utf-8"?>
<ScrollView
...>
<LinearLayout ...
...>
<WebView
android:id="@+id/helpwithwebview"
android:layout_width="match_parent"
android:layout_height="200dip"
android:layout_weight="1.0"/>
<Button
...
android:text="Exit"/>
</LinearLayout>
</ScrollView>

4
Embedded WebView: Java
// HelpWebViewFragment.java
public View onCreateView(. . .) {
View v = inflater.inflate(R.layout.fragment_help_webview, ...);
WebView helpInWebView = v.findViewById(R.id.helpwithwebview);
mProgressBar = v.findViewById(R.id.webviewprogress);
mProgressBar.setMax(100);
View buttonExit = v.findViewById(R.id.button_exit);
buttonExit.setOnClickListener(this);
Bundle extras = getActivity().getIntent().getExtras();
if (extras != null) {
mUrl = extras.getString(ARG_URI); /* . . . */
}
// . . .
helpInWebView.loadUrl(mUrl);
return v;
}
5
Embedded WebView: Kotlin
// HelpWebViewFragment.kt
override fun onCreateView( . . . ): View? {
val v = inflater.inflate(R.layout.fragment_help_webview, . . .)
val helpInWebView = v.findViewById(R.id.helpwithwebview)
mProgressBar = v.findViewById(R.id.webviewprogress)
mProgressBar.apply { max = 100 }
val buttonExit = v.findViewById<Button>(R.id.button_exit)
buttonExit.setOnClickListener(this)
val extras = activity.intent.extras
if (extras != null) {
mUrl = extras.getString(ARG_URI)
}
/* . . . */
helpInWebView.loadUrl(mUrl)
return v
}
6
Location-Based Applications
These mix-and-match the following actions:
– Opening a map
– Invoking a geocoding service on a point of
interest
– Navigating the map to a position or make a
map-based calculation
– Determining the user’s geolocation from the
device (latitude, longitude)

7
Additional Requirements for Maps
• Use built-in GoogleMap with a FragmentActivity
• Link against Google APIs for Android (not “Android SDK”)
• Request permissions: <uses-permission
android:name="<permission>"/>, where <permission>
includes ACCESS_NETWORK_STATE,
ACCESS_COARSE_LOCATION, ACCESS_FINE_LOCATION,
WRITE_EXTERNAL_STORAGE READ_GSERVICES
• Request a Map API key: https://developers.google.com/maps/
documentation/android/start
• Need OpenGL ES v2: <uses-feature
android:glEsVersion="0x00020000”
android:required="true"/>
8
Map Fragment Layout
<fragment
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="@+id/map"
tools:context=".MapsActivity"
android:name="com.google.android.gms.maps.
SupportMapFragment"/>

• Google Maps uses Fragments


• UI Fragment loaded dynamically

9
Map Fragment Code: Java (1)
// MapsFragment.java
public class MapsFragment extends SupportMapFragment implements
OnMapReadyCallback {
private GoogleMap mMap;
private GoogleApiClient mApiClient;
private static final String[] LOCATION_PERMISSIONS = new String[] {
Manifest.permission.ACCESS_FINE_LOCATION,
Manifest.permission.ACCESS_COARSE_LOCATION };
private FusedLocationProviderClient mFusedLocationProviderClient;
private Location mLocation;
private LatLng mDefaultLocation;
private static final int REQUEST_LOCATION_PERMISSIONS = 0;
private boolean mLocationPermissionGranted = false;
. . .

// MapsActivity.java just uses a SingleFragmentActivity

10
Map Fragment Code: Java (2)
// MapsFragment.java (continued)
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setHasOptionsMenu(true);
mApiClient = new GoogleApiClient.Builder(getActivity())
.addApi(LocationServices.API)
.addConnectionCallbacks(new GoogleApiClient.ConnectionCallbacks() {
@Override
public void onConnected(@Nullable Bundle bundle) {
getActivity().invalidateOptionsMenu(); }

@Override
public void onConnectionSuspended(int i) { /*...*/ } }).build();
getMapAsync(this);
}

@Override
public void onResume() {
super.onResume();
setUpEula(); 11
findLocation(); }
Map Fragment Code: Java (3)
// MapsFragment.java (continued)
@Override
public void onStart() { mApiClient.connect(); }

@Override
public void onStop() { mApiClient.disconnect(); }

private void findLocation() {


updateLocationUI();
if (hasLocationPermission()) {
mFusedLocationProviderClient = LocationServices.getFusedLocationProviderClient(
getActivity());
mDefaultLocation = new LatLng(40.0, -83.0);
LocationRequest locationRequest = LocationRequest.create();
/* Set location request parameters */
FusedLocationProviderClient locationProvider =
LocationServices.getFusedLocationProviderClient(getActivity());
Task locationResult = locationProvider.getLastLocation();
locationResult.addOnCompleteListener(getActivity(), new OnCompleteListener() {
@Override
public void onComplete(@NonNull Task task) {
if (task.isSuccessful()) {/* Move camera */ } } else { /* ... */ } }});}
12
// Else request permissions, end of method.
Map Fragment Code: Java (4)
// MapsFragment.java (continued)
private void setUpEula() {
mSettings = getActivity().getSharedPreferences(getString(R.string.prefs), 0);
boolean isEulaAccepted = mSettings.getBoolean(getString(R.string.eula_accepted_key),
false);
if (!isEulaAccepted) {
DialogFragment eulaDialogFragment = new EulaDialogFragment();
eulaDialogFragment.show(getActivity().getSupportFragmentManager(), "eula"); }
}

@Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) { // . . .
inflater.inflate(R.menu.maps_menu, menu); }

@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case R.id.menu_showcurrentlocation:
Log.d(TAG, "Showing current location");
if (hasLocationPermission()) { findLocation(); }
else { /* Request permissions */ }
break; }
return true; 13
}
Map Fragment Code: Java (5)
// MapsFragment.java (continued)
@Override
public void onRequestPermissionsResult(. . .) {
mLocationPermissionGranted = false;
switch (requestCode) {
case REQUEST_LOCATION_PERMISSIONS: {
// If request is cancelled, the result arrays are empty.
if (grantResults.length > 0 &&
grantResults[0]==PackageManager.PERMISSION_GRANTED) {
mLocationPermissionGranted = true; } } }
updateLocationUI(); }

private void updateLocationUI() {


if (mMap == null) { return; }
if (mLocationPermissionGranted) { /* Enable location */ }
else { /* Disable location, request permissions */ }
}

@Override
public void onMapReady(GoogleMap googleMap) {
mMap = googleMap;
mMap.addMarker(new MarkerOptions().position(new LatLng(40.0,-83.0)).title("O.S.U."));
}
14
private boolean hasLocationPermission() { /* . . . */ }
Map Fragment Code: Kotlin (1)
// MapsFragment.kt
class MapsFragment : SupportMapFragment(), OnMapReadyCallback {
private lateinit var mMap: GoogleMap
private lateinit var mApiClient: GoogleApiClient
private lateinit var mFusedLocationProviderClient: FusedLocationProviderClient
private var mLocation: Location? = null
private var mDefaultLocation: LatLng? = null
private var mLocationPermissionGranted = false
private var mMapReady = false

companion object {
private val LOCATION_PERMISSIONS = arrayOf(
Manifest.permission.ACCESS_FINE_LOCATION,
Manifest.permission.ACCESS_COARSE_LOCATION)
private val REQUEST_LOCATION_PERMISSIONS = 0
}

15
Map Fragment Code: Kotlin (2)
// MapsFragment.kt (continued)
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setHasOptionsMenu(true)

mApiClient = GoogleApiClient.Builder(activity)
.addApi(LocationServices.API)
.addConnectionCallbacks(object: GoogleApiClient.ConnectionCallbacks {
override fun onConnected(bundle: Bundle?) { /* ... */ }
override fun onConnectionSuspended(i: Int) { /* ... */ }
}).build()
getMapAsync(this)
}

override fun onResume() {


super.onResume()
setUpEula()
findLocation()
}
16
Map Fragment Code: Kotlin (3)
// MapsFragment.kt (continued)
override fun onStart() { mApiClient.connect() }

override fun onStop() { mApiClient.disconnect() }

private fun findLocation() {


updateLocationUI()
if (hasLocationPermission()) {
mFusedLocationProviderClient =
LocationServices.getFusedLocationProviderClient(activity)
mDefaultLocation = LatLng(40.0, -83.0)
val locationRequest = LocationRequest.create()
/* Set locationRequest properties */
val locationProvider = LocationServices.getFusedLocationProviderClient(activity)
val locationResult = locationProvider.lastLocation
locationResult.addOnCompleteListener(activity, object:OnCompleteListener<Location> {
override fun onComplete(task: Task<Location>) {
if (task.isSuccessful) {
// Set map's camera position to current device location
} else { /* Disable location */ } } }) }
// Else request permissions, end of method.
17
Map Fragment Code: Kotlin (4)
// MapsFragment.kt (continued)
private fun setUpEula() {
mSettings = activity.getSharedPreferences(getString(R.string.prefs), 0)
val isEulaAccepted = mSettings!!.getBoolean(getString(R.string.eula_accepted_key),
false)
if (!isEulaAccepted) {
val eulaDialogFragment = EulaDialogFragment()
eulaDialogFragment.show(activity.supportFragmentManager, "eula") }
}

override fun onCreateOptionsMenu(menu: Menu?, inflater: MenuInflater?) {


super.onCreateOptionsMenu(menu, inflater)
inflater?.inflate(R.menu.maps_menu, menu)
}

override fun onOptionsItemSelected(item: MenuItem?): Boolean {


when (item?.itemId) {
R.id.menu_showcurrentlocation -> {
if (hasLocationPermission()) { findLocation() }
else { requestPermissions(LOCATION_PERMISSIONS,REQUEST_LOCATION_PERMISSIONS) }
}
}
} 18
Map Fragment Code: Kotlin (5)
// MapsFragment.kt (continued)
override fun onRequestPermissionsResult(requestCode: Int, permissions: Array<String>,

grantResults: IntArray) {
mLocationPermissionGranted = false
when (requestCode) {
REQUEST_LOCATION_PERMISSIONS -> {
// If request is cancelled, the result arrays are empty.
if (grantResults.isNotEmpty() &&
grantResults[0] == PackageManager.PERMISSION_GRANTED) {
mLocationPermissionGranted = true } } }
updateLocationUI() }

private fun updateLocationUI() {


if (mMapReady) {
if (mLocationPermissionGranted) { /* Enable location */ }
else { /* Disable location, request permissions */ }
} }

override fun onMapReady(googleMap: GoogleMap) {


mMap = googleMap /* Prepare map; set mMapReady to true */ } 19
Map Menu Layout
<menu
<!-- Details omitted --> >
<item
android:id="@+id/
menu_showcurrentlocation"
android:orderInCategory="100"
android:title="@string/show_location"
android:icon="@android:drawable/
ic_menu_mylocation"
app:showAsAction="ifRoom"/>
</menu>

20
License Agreement Fragment: Java
• We need to get the user’s consent
public class EulaDialogFragment extends DialogFragment {
public void setEulaAccepted() {
SharedPreferences prefs = getActivity().getSharedPreferences(
getString(R.string.prefs), 0);
SharedPreferences.Editor editor = prefs.edit();
editor.putBoolean(getString(R.string.eula_accepted_key), true)
.apply(); }

@Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
builder.setTitle(R.string.eula_title)
.setMessage(Html.fromHtml(getString(R.string.eula)))
.setPositiveButton(R.string.accept, new DialogInterface.OnClickListener() {
/* Call setEulaAccepted() */ } })
.setNegativeButton(R.string.decline, new DialogInterface.OnClickListener() {
/* Cancel dialog, finish activity */
return builder.create(); }
}
21
License Agreement Fragment: Kotlin
class EulaDialogFragment : DialogFragment() {

fun setEulaAccepted() {
val prefs = activity.getSharedPreferences(getString(R.string.prefs), 0)
val editor = prefs.edit()
editor.putBoolean(getString(R.string.eula_accepted_key), true).apply()
}

override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {


// Use the Builder class for convenient dialog construction
val builder = AlertDialog.Builder(activity)
builder.setTitle(R.string.about_app)
.setMessage(Html.fromHtml(getString(R.string.eula)))
.setPositiveButton(R.string.accept) { /* Call setEulaAccepted() */ }
.setNegativeButton(R.string.decline) {
/* Cancel dialog, finish activity */
}
return builder.create()
}
}

22
Location Determination Practices
• Ways to get location:
– GPS
– Cellular
– Wi-Fi
• Best practices for location-based apps:
– Check for connectivity
– Use threading to ensure responsiveness (Note:
Threading built-in for many SDK components)

23
Thank You

Questions and comments?

24
References
• Chapter 10: “Channeling the Outside World through your Android
Device” from Android SDK 3 Programming for Dummies
• Chapters 33–34: “Locations and Play Services” and “Maps” from
Android Programming: The Big Nerd Ranch Guide (3rd ed.)
• http://developer.android.com/reference/android/webkit/package-summ
ary.html
• http://developer.android.com/reference/android/webkit/WebView.html
• https://developers.google.com/maps/documentation/android/start
• https://developer.android.com/guide/components/fragments.html
• https://developer.android.com/training/basics/fragments/creating.html

25

You might also like

pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy