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: Dr. 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 = 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; }

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

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 (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: documentation/android/start Need OpenGL ES v2: <uses-feature android:glEsVersion="0x ” android:required="true"/>

9 Map Fragment Layout Google Maps uses Fragments
<fragment 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 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() { 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(); /* Set location request parameters */ FusedLocationProviderClient locationProvider = LocationServices.getFusedLocationProviderClient(getActivity()); Task locationResult = locationProvider.getLastLocation(); locationResult.addOnCompleteListener(getActivity(), new OnCompleteListener() public void Task task) { if (task.isSuccessful()) {/* Move camera */ } } else { /* ... */ } }});} // 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; } if (mLocationPermissionGranted) { /* Enable location */ } else { /* Disable location, request permissions */ } 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() { /* */ }

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

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 -> { if (hasLocationPermission()) { findLocation() } else { requestPermissions(LOCATION_PERMISSIONS,REQUEST_LOCATION_PERMISSIONS) } } } }

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

20 Map Menu Layout <menu <!-- Details omitted --> > <item menu_showcurrentlocation" android:orderInCategory="100" ic_menu_mylocation" app:showAsAction="ifRoom"/> </menu>

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

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) { /* Call setEulaAccepted() */ } .setNegativeButton(R.string.decline) { /* Cancel dialog, finish activity */ } return builder.create() } }

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

24 Questions and comments?
Thank You Questions and comments?

25 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


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

Similar presentations


Ads by Google