External Services CSE 5236: Mobile Application Development

Slides:



Advertisements
Similar presentations
CE881: Mobile and Social Application Programming Simon M. Lucas Menus and Dialogs.
Advertisements

Location-Based Services: Part 2 (Google Maps)
Android Fragments A very brief introduction Android Fragments1.
Mobile Programming Lecture 6
Android Programming-Activity Lecture 4. Activity Inside java folder Public class MainActivity extends ActionBarActivity(Ctrl + Click will give you the.
Networking: Part 1 (Web Content). Networking with Android Android provides A full-featured web browser based on Chromium, the open source browser engine.
Cosc 4730 Android Fragments. Fragments You can think of a fragment as a modular section of an activity, which has its own lifecycle, receives its own.
Maps Dr. David Janzen Except as otherwise noted, the content of this presentation is licensed under the Creative Commons Attribution 2.5 License.
Android Using Menus Notes are based on: The Busy Coder's Guide to Android Development by Mark L. Murphy Copyright © CommonsWare, LLC. ISBN:
Styles, Dialog Boxes, and Menus. Styles Allow creation of a common format – placed in res/values/styles.xml – file name is incidental Can be applied.
Mobile Programming Lecture 7 Dialogs, Menus, and SharedPreferences.
Android Application Lifecycle and Menus
TCS Internal Maps. 2 TCS Internal Objective Objective :  MAPS o Integration of Maps.
Android Alert Dialog. Alert Dialog Place Button to open the dialog. public class MainActivity extends ActionBarActivity { private static Button button_sbm;
Cosc 5/4735 YouTube API. YouTube The YouTube Android Player API enables you to incorporate video playback functionality into your Android applications.
Activities and Intents Chapter 3 1. Objectives Explore an activity’s lifecycle Learn about saving and restoring an activity Understand intents and how.
Developing for Chromecast Cast Companion Library & Custom Receiver Application.
Lecture 5: Location Topics: Google Play Services, Location API Date: Feb 16, 2016.
School of Engineering and Information and Communication Technology KIT305/KIT607 Mobile Application Development Android OS –Permissions (cont.), Fragments,
Lecture 5: Location Topics: Google Play Services, Location API
Location Services: Part 1 (Location and Geocoding)
Lab7 – Appendix.
Introduction to android
Google VR (gvr) CardBoard and DayDream With OpenGL
Permissions.
Android Programming - Features
Lecture 5: Location Topics: Google Play Services, Location API.
Location-Based Services: Part 2 (Google Maps)
several communicating screens
CS240: Advanced Programming Concepts
GUI Programming Fundamentals
Android Studio, Android System Basics and Git
Concurrency in Android
CS499 – Mobile Application Development
Designing Apps Using The WebView Control
Android Location Based Services
Android – Read/Write to External Storage
Android Introduction Camera.
תכנות ב android אליהו חלסצ'י.
ANDROID UI – FRAGMENTS UNIT II.
CIS 470 Mobile App Development
CIS 470 Mobile App Development
Developing Android Services
CIS 470 Mobile App Development
CIS 470 Mobile App Development
CIS 470 Mobile App Development
CIS 470 Mobile App Development
Programming with Android: The Google Maps Library
Android Sensor Programming
CMPE419 Mobile Application Development
Activities and Intents
CIS 470 Mobile App Development
CIS 470 Mobile App Development
CIS 470 Mobile App Development
CIS 470 Mobile App Development
Lecture 5: Location Topics: Google Play Services, Location API.
Objects First with Java
CMPE419 Mobile Application Development
CS 240 – Advanced Programming Concepts
Mobile Programming Dr. Mohsin Ali Memon.
Implication of Orientation Changes
Activities, Fragments, and Intents
Android Application Model I
User Interface Development
Introduction to Mobile Apps
Mobile Programming Broadcast Receivers.
Android Sensor Programming
CA16R405 - Mobile Application Development (Theory)
External Services CSE 5236: Mobile Application Development
User Interface Development
Presentation transcript:

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)

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

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: http://en.wikipedia.org/wiki/Tictactoe 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>

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

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 }

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)

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 https://developers.google.com/maps/documentation/android/start Need OpenGL ES v2: <uses-feature android:glEsVersion="0x00020000” android:required="true"/>

Map Fragment Layout Google Maps uses Fragments <fragment 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" android:id="@+id/map" tools:context=".MapsActivity" android:name="com.google.android.gms.maps.SupportMapFragment"/> Google Maps uses Fragments UI Fragment needs to be loaded dynamically…

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

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(); findLocation(); }

Map Fragment Code: Java (3) // MapsFragment.java (continued) @Override public void onStart() { // . . . getActivity().invalidateOptionsMenu(); 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(); 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() { @Override public void onComplete(@NonNull 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.

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

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; } try { if (mLocationPermissionGranted) { /* Enable location */ } else { /* Disable location, request permissions */ } } catch (SecurityException e) { /* . . . */ } } @Override 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() { /* . . . */ }

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 }

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

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.

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 }

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 { /* . . . */ }

Map Menu Layout <menu xmlns:app= "http://schemas.android.com/apk/res-auto" xmlns:android= "http://schemas.android.com/apk/res/android"> <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>

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(); } }

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

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)

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

Questions and comments? Thank You Questions and comments?