Presentation is loading. Please wait.

Presentation is loading. Please wait.

External Services CSE 5236: Mobile Application Development

Similar presentations


Presentation on theme: "External Services CSE 5236: Mobile Application Development"— Presentation transcript:

1 External Services CSE 5236: Mobile Application Development
Course Coordinator: Dr. Rajiv Ramnath Instructor: Adam C. Champion Reading: Big Nerd Ranch Guide, Chap. 30 (WebView); Chaps. 33, 34 (Google Play services, maps)

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

3 Invoking Browser App Java Kotlin
// HelpFragment.java private void launchBrowser( String url) { Uri theUri = Uri.parse(url); Intent LaunchBrowserIntent = new Intent(Intent.ACTION_VIEW, theUri); startActivity( LaunchBrowserIntent); } // HelpFragment.kt private fun launchBrowser( url: String) { val theUri = Uri.parse(url) val LaunchBrowserIntent = Intent(Intent.ACTION_VIEW, theUri) startActivity( LaunchBrowserIntent) } URL: Note: Activity stacking due to re-launch of browser on mobile page

4 Embedded WebView - Layout
<?xml version="1.0" encoding="utf-8"?> <ScrollView ...> <LinearLayout ... <WebView android:layout_width="match_parent" android:layout_height="200dip" android:layout_weight="1.0"/> <Button ... android:text="Exit"/> </LinearLayout> </ScrollView>

5 Embedded WebView: Java
// HelpWebViewFragment.java public View onCreateView(. . .) { View v = inflater.inflate(R.layout.fragment_help_webview, ...); WebView helpInWebView = (WebView) v.findViewById(R.id.helpwithwebview); mProgressBar = (ProgressBar) 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.setWebViewClient(new WebViewClient() { public boolean shouldOverrideUrlLoading(. . .) { return false; } }); helpInWebView.setWebChromeClient(new WebChromeClient() { public void onProgressChanged(WebView webView, int progress) { if (progress == 100) { mProgressBar.setVisibility(View.GONE); } else { mProgressBar.setVisibility(View.VISIBLE); mProgressBar.setProgress(progress); } } }); helpInWebView.loadUrl(mUrl); return v; }

6 Embedded WebView: Kotlin
// HelpWebViewFragment.kt override fun onCreateView( ): View? { val v = inflater.inflate(R.layout.fragment_help_webview, . . .) val helpInWebView = v.findViewById<WebView>(R.id.helpwithwebview) mProgressBar = v.findViewById<ProgressBar>(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) } WebView.setWebContentsDebuggingEnabled(true) helpInWebView.settings.javaScriptEnabled = true helpInWebView.webViewClient = object : WebViewClient() { override fun shouldOverrideUrlLoading(. . . ): Boolean { return false }} helpInWebView.webChromeClient = object : WebChromeClient() { override fun onProgressChanged( ) { if (progress == 100) { mProgressBar.visibility = View.GONE } else { mProgressBar.visibility = View.VISIBLE mProgressBar.progress = progress } } } helpInWebView.loadUrl(mUrl) return v }

7 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)

8 Additional Requirements for Maps
Use built-in GoogleMap with a FragmentActivity Link against Google APIs for Android (rather than standard Android SDK) Declare the use of the Google map package: <uses-library android:name="com.google.android.maps”/> Request the appropriate permissions, e.g.: <uses-permission android:name="android.permission.INTERNET"/> <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/> <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/> <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/> <uses-permission android:name="com.google.android.providers.gsf.permission.READ_GSERVICES”/> Request a Map API key Goes in AndroidManifest.xml as <meta-data android:name="com.google.android.maps.v2.API_KEY” android:value=“...”/> See Need OpenGL ES v2: <uses-feature android:glEsVersion="0x ” android:required="true"/>

9 Map Fragment Layout Google Maps uses Fragments
<fragment xmlns:android=" xmlns:tools=" android:layout_width="match_parent" android:layout_height="match_parent" tools:context=".MapsActivity" android:name="com.google.android.gms.maps.SupportMapFragment"/> Google Maps uses Fragments UI Fragment needs to be loaded dynamically…

10 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

11 Map Fragment Code: Java (2)
// MapsFragment.java public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setHasOptionsMenu(true); mApiClient = new GoogleApiClient.Builder(getActivity()) .addApi(LocationServices.API) .addConnectionCallbacks(new GoogleApiClient.ConnectionCallbacks() public void Bundle bundle) { getActivity().invalidateOptionsMenu(); public void onConnectionSuspended(int i) { } }).build(); getMapAsync(this); public void onResume() { super.onResume(); setUpEula(); findLocation(); }

12 Map Fragment Code: Java (3)
// MapsFragment.java public void onStart() { // getActivity().invalidateOptionsMenu(); mApiClient.connect(); 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(); locationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY); locationRequest.setNumUpdates(1); locationRequest.setInterval(0); FusedLocationProviderClient locationProvider = LocationServices.getFusedLocationProviderClient(getActivity()); Task locationResult = locationProvider.getLastLocation(); locationResult.addOnCompleteListener(getActivity(), new OnCompleteListener() public void Task task) { if (task.isSuccessful()) { mLocation = (Location) task.getResult(); mMap.moveCamera(CameraUpdateFactory.newLatLngZoom(new LatLng(mLocation.getLatitude(), mLocation.getLongitude()), 16)); } else { /* Disable Location */ } } }); } // Else request permissions, end of method.

13 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"); } public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) { // inflater.inflate(R.menu.maps_menu, menu); 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; }

14 Map Fragment Code: Java (5)
// MapsFragment.java 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; } try { if (mLocationPermissionGranted) { /* Enable location */ } else { /* Disable location, request permissions */ } } catch (SecurityException e) { /* */ } public void onMapReady(GoogleMap googleMap) { mMap = googleMap; mMap.addMarker(new MarkerOptions().position(new LatLng(40.0, -83.0)).title("Ohio State University")); mMap.setMyLocationEnabled(true); mMap.getUiSettings().setMyLocationButtonEnabled(true); /* */ } private boolean hasLocationPermission() { /* */ }

15 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 }

16 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?) { activity.invalidateOptionsMenu() } override fun onConnectionSuspended(i: Int) { } }).build() getMapAsync(this) } override fun onResume() { super.onResume() setUpEula() findLocation() }

17 Map Fragment Code: Kotlin (3)
// MapsFragment.kt (continued) override fun onStart() { // activity.invalidateOptionsMenu() 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() locationRequest.priority = LocationRequest.PRIORITY_HIGH_ACCURACY locationRequest.numUpdates = 1 locationRequest.interval = 0 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 the map's camera position to the current location of the device. mLocation = task.result as Location mMap.moveCamera(CameraUpdateFactory.newLatLngZoom( LatLng(mLocation!!.latitude, mLocation!!.longitude), 16f)) } else { /* Disable location */ } } }) } // Else request permissions, end of method.

18 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 -> { Log.d(TAG, "Showing current location") if (hasLocationPermission()) { findLocation() } else { requestPermissions(LOCATION_PERMISSIONS, REQUEST_LOCATION_PERMISSIONS) } } } return true }

19 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) { try { if (mLocationPermissionGranted) { mMap.isMyLocationEnabled = true mMap.uiSettings.isMyLocationButtonEnabled = true } else { /* Disable location, request permissions */ } } catch (e: SecurityException) { Log.e("Exception: %s", e.message) } } /* */ } override fun onMapReady(googleMap: GoogleMap) { mMap = googleMap mMap.addMarker(MarkerOptions().position(LatLng(40.0, -83.0)).title("Ohio State University")) try { mMap.isMyLocationEnabled = true mMap.uiSettings.isMyLocationButtonEnabled = true } catch (se: SecurityException) { Log.e(TAG, "Location not enabled, skipping") } mMap.isBuildingsEnabled = true mMap.isIndoorEnabled = true mMapReady = true } private fun hasLocationPermission(): Boolean { /* */ }

20 Map Menu Layout <menu xmlns:app= " xmlns:android= " <item android:orderInCategory="100" ic_menu_mylocation" app:showAsAction="ifRoom"/> </menu>

21 License Agreement Fragment: Java
Yes, this is required… 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() { public void onClick(DialogInterface dialog, int id) { setEulaAccepted(); } }) .setNegativeButton(R.string.decline, new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int which) { dialog.cancel(); getActivity().finish(); } }); return builder.create(); } }

22 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) { dialog, id -> setEulaAccepted() } setNegativeButton(R.string.decline) { dialog, which -> dialog.cancel() activity.finish() } return builder.create() } }

23 Location Determination and Practices
Types: GPS Cellular WiFi Best practices for location-based applications: Check for connectivity Use threading to ensure responsiveness (Note: Threading built-in for many SDK components)

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.) summary.html

25 Questions and comments?
Thank You Questions and comments?


Download ppt "External Services CSE 5236: Mobile Application Development"

Similar presentations


Ads by Google