External Services CSE 5236: Mobile Application Development

Slides:



Advertisements
Similar presentations
CE881: Mobile and Social Application Programming Simon M. Lucas Quiz, Walkthrough, Exercise, Lifecycles, Intents.
Advertisements

CE881: Mobile and Social Application Programming Simon M. Lucas Menus and Dialogs.
Location-Based Services: Part 2 (Google Maps)
Data Storage: Part 1 (Preferences)
Android Fragments A very brief introduction Android Fragments1.
Programming Concepts. Derive a new class from Activity of the framework Prepare the data beforehand, e.g., vertices, colours, normal vectors, texture.
Android Tutorial Team 3 Jerry Yu Mayank Mandava Mu Du Will Wangles.
Mobile Programming Lecture 6
Android Programming-Activity Lecture 4. Activity Inside java folder Public class MainActivity extends ActionBarActivity(Ctrl + Click will give you the.
Create Navigation Drawer Team 2 Zhong Wang Jiaming Dong Philip Wu Lingduo Kong.
Networking: Part 1 (Web Content). Networking with Android Android provides A full-featured web browser based on Chromium, the open source browser engine.
© 2016 Cengage Learning®. May not be scanned, copied or duplicated, or posted to a publicly accessible website, in whole or in part. Android Boot Camp.
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;
Activities and Intents Chapter 3 1. Objectives Explore an activity’s lifecycle Learn about saving and restoring an activity Understand intents and how.
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,
Fragments and Menus Chapter 4 1. Objectives Learn three different types of menus: options, context, and popup Learn to configure the ActionBar and Toolbar.
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
Android Application -Architecture.
Permissions.
Android Programming - Features
Lecture 5: Location Topics: Google Play Services, Location API.
Location-Based Services: Part 2 (Google Maps)
CS240: Advanced Programming Concepts
GUI Programming Fundamentals
Concurrency in Android
CS499 – Mobile Application Development
Designing Apps Using The WebView Control
Mobile Application Development Chapter 4 [Android Navigation and Interface Design] IT448-Fall 2017 IT448- Fall2017.
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
CIS 470 Mobile App Development
CIS 470 Mobile App Development
CIS 470 Mobile App Development
Programming with Android: The Google Maps Library
Many thanks to Jun Bum Lim for his help with this tutorial.
Activities and Intents
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
Activities and Intents
Activities and Fragments
CS 240 – Advanced Programming Concepts
Mobile Programming Dr. Mohsin Ali Memon.
Implication of Orientation Changes
Activities, Fragments, and Intents
Android Application Model I
External Services CSE 5236: Mobile Application Development
User Interface Development
Introduction to Mobile Apps
Android Sensor Programming
CA16R405 - Mobile Application Development (Theory)
User Interface Development
Presentation transcript:

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)

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

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 }

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 (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"/>

Map Fragment Layout Google Maps uses Fragments <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

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() { 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 { /* ... */ } }});} // 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; } 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.")); } 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?) { /* ... */ } 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() { 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.

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

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 */ } private fun hasLocationPermission(): Boolean { /* . . . */ }

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>

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

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

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)

Questions and comments? Thank You Questions and comments?

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