DEV Community

HMS Community
HMS Community

Posted on

Search the hospitals using Huawei Map Kit, Site Kit and Location Kit in Patient Tracking Android app (Kotlin) – Part 5

Image description

Introduction
In this article, we can learn how to search the hospitals located by source and destination address with HMS Core Kits such as Map, Site, and Location Kits. Map kit is to display maps, it covers map data of more than 200 countries and regions for searching any location address. Location kit provides to get the current location and location updates, and it provides flexible location based services globally to the users. Site kit provides with convenient and secure access to diverse, place-related services to users.

So, I will provide a series of articles on this Patient Tracking App, in upcoming articles I will integrate other Huawei Kits.

If you are new to this application, follow my previous articles.

https://forums.developer.huawei.com/forumPortal/en/topic/0201902220661040078

https://forums.developer.huawei.com/forumPortal/en/topic/0201908355251870119

https://forums.developer.huawei.com/forumPortal/en/topic/0202914346246890032

https://forums.developer.huawei.com/forumPortal/en/topic/0202920411340450018

Map Kit

Map Kit covers map data of more than 200 countries and regions, and supports over 70 languages. User can easily integrate map-based functions into your apps using SDK. It optimizes and enriches the map detail display capability. Map Kit supports gestures including zoom, rotation, moving and tilt gestures to ensure smooth interaction experience.

Location Kit

Location Kit combines the GPS, Wi-Fi and base station location functionalities in your app to build up global positioning capabilities, allows to provide flexible location-based services targeted at users around globally. Currently, it provides three main capabilities: fused location, activity identification and geo-fence. You can call one or more of these capabilities as required.

Site Kit

Site Kit provides the place related services for apps. It provides that to search places with keywords, find nearby place, place suggestion for user search, and find the place details using the unique id.

Requirements

  1. Any operating system (MacOS, Linux and Windows).
  2. Must have a Huawei phone with HMS 4.0.0.300 or later.
  3. Must have a laptop or desktop with Android Studio, Jdk 1.8, SDK platform 26 and Gradle 4.6 and above installed.
  4. Minimum API Level 24 is required.
  5. Required EMUI 9.0.0 and later version devices.

How to integrate HMS Dependencies

  • First register as Huawei developer and complete identity verification in Huawei developers website, refer to register a Huawei ID.

  • Create a project in android studio, refer Creating an Android Studio Project.

  • Generate a SHA-256 certificate fingerprint.

  • To generate SHA-256 certificate fingerprint. On right-upper corner of android project click Gradle, choose Project Name > Tasks > android, and then click signingReport, as follows.

Image description

Note: Project Name depends on the user created name.

Image description

  • Enter SHA-256 certificate fingerprint and click Save button, as follows.

Image description

  • Click Manage APIs tab and enable Map Kit, Site Kit and Location Kit.

  • Add the below maven URL in build.gradle(Project) file under the repositories of buildscript, dependencies and allprojects, refer Add Configuration.

maven { url 'http://developer.huawei.com/repo/' }
classpath 'com.huawei.agconnect:agcp:1.6.0.300'

Enter fullscreen mode Exit fullscreen mode
  • Add the below plugin and dependencies in build.gradle(Module) file.
apply plugin: 'com.huawei.agconnect'
// Huawei AGC
implementation 'com.huawei.agconnect:agconnect-core:1.6.0.300'
// Huawei Map
implementation 'com.huawei.hms:maps:6.2.0.301'
// Huawei Site Kit
implementation 'com.huawei.hms:site:6.2.0.301'
// Huawei Location Kit
implementation 'com.huawei.hms:location:6.2.0.300'
Enter fullscreen mode Exit fullscreen mode
  • Now Sync the gradle.

  • Add the required permission to the AndroidManifest.xml file.

<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
<uses-permission android:name="com.huawei.appmarket.service.commondata.permission.GET_COMMON_DATA"/>
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="android.permission.CHANGE_WIFI_STATE"/>
// To obtain the coarse longitude and latitude of a user with Wi-Fi network or base station.
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
// To receive location information from satellites through the GPS chip.
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
<uses-permission android:name="android.permission.ACCESS_BACKGROUND_LOCATION" />
Enter fullscreen mode Exit fullscreen mode

Let us move to development

I have created a project on Android studio with empty activity let us start coding.

In the SearchActivity.kt we can find the business logic.

class SearchActivity : AppCompatActivity(), OnMapReadyCallback, View.OnClickListener {

    private lateinit var hmap: HuaweiMap
    private lateinit var mMapView: MapView
    private var mMarker: Marker? = null
    private var mCircle: Circle? = null
    private var isSourceAddressField: Boolean = false
    private var pickupLat: Double = 0.0
    private var pickupLng: Double = 0.0
    private var dropLat: Double = 0.0
    private var dropLng: Double = 0.0
    private var searchService: SearchService? = null
    private var searchIntent: SearchIntent? = null
    private lateinit var mFusedLocationProviderClient: FusedLocationProviderClient
    companion object {
        private const val TAG = "MapViewDemoActivity"
        private const val MAPVIEW_BUNDLE_KEY = "MapViewBundleKey"
        private val LAT_LNG = LatLng(12.9716, 77.5946)
    }

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_search)

        // Get mapView
        mMapView = findViewById(R.id.mapView)
        var mapViewBundle: Bundle? = null
        if (savedInstanceState != null) {
            mapViewBundle = savedInstanceState.getBundle(MAPVIEW_BUNDLE_KEY)
        }
        // Add "Your API key" in api_key field value
        MapsInitializer.setApiKey("DAEDADRgIFzXbAJpOqImvjRAGRkmm3wGTux0O6JBiaddIPMNTJ4SawIN8ZHWu28dtc1f1H3Cqzh0LC1cgYIvBnl1edWVuWkjciH4NA==")
        mMapView.onCreate(mapViewBundle)
        // get map by async method
        mMapView.getMapAsync(this)
        //Checking permission
        checkLocationPermission()
        // Location service
        mFusedLocationProviderClient = LocationServices.getFusedLocationProviderClient(this)
        //Initialize Search Service
        getLocationFromService()
        //Initialize OnClickListener
        customCurrentLocation.setOnClickListener(this)
        pickUpLocation.setOnClickListener(this)
        dropLocation.setOnClickListener(this)

    }

    override fun onMapReady(map: HuaweiMap?) {
        Log.d(TAG, "onMapReady: ")
        // Get the HuaweiMap instance in this call back method.
        hmap = map!!
        // Move camera by CameraPosition param, latlag and zoom params can set here.
        val build = CameraPosition.Builder().target(LatLng(13.0827, 80.2707)).zoom(10f).build()
        val cameraUpdate = CameraUpdateFactory.newCameraPosition(build)
        hmap.animateCamera(cameraUpdate)
        hmap.setMaxZoomPreference(10f)
        hmap.setMinZoomPreference(1f)
        // Marker can be add by HuaweiMap
        mMarker = hmap.addMarker(
            MarkerOptions().position(LAT_LNG)
                .icon(BitmapDescriptorFactory.fromResource(R.drawable.garden_icon))
                .clusterable(true))
        mMarker?.showInfoWindow()
        // circle can be add by HuaweiMap
        mCircle = hmap.addCircle(
            CircleOptions().center(LatLng(28.7041, 77.1025)).radius(45000.0).fillColor(Color.GREEN))
        mCircle?.fillColor = Color.TRANSPARENT

    }

    override fun onStart() {
        super.onStart()
        mMapView.onStart()
    }
    override fun onStop() {
        super.onStop()
        mMapView.onStop()
    }
    override fun onDestroy() {
        super.onDestroy()
        mMapView.onDestroy()
    }
    override fun onPause() {
        mMapView.onPause()
        super.onPause()
    }
    override fun onResume() {
        super.onResume()
        mMapView.onResume()
    }

    private fun checkLocationPermission() {
        // check location permission
        if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.P) {
            if (ActivityCompat.checkSelfPermission(this, ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED
                && ActivityCompat.checkSelfPermission(this, ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
                val strings = arrayOf(ACCESS_FINE_LOCATION, ACCESS_COARSE_LOCATION)
                ActivityCompat.requestPermissions(this, strings, 1)
            }
        }  else {
            if (ActivityCompat.checkSelfPermission(this, ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED
                && ActivityCompat.checkSelfPermission(this,ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED
                && ActivityCompat.checkSelfPermission(this,"android.permission.ACCESS_BACKGROUND_LOCATION") != PackageManager.PERMISSION_GRANTED) {
                val strings = arrayOf(ACCESS_FINE_LOCATION, ACCESS_COARSE_LOCATION,
                    "android.permission.ACCESS_BACKGROUND_LOCATION")
                ActivityCompat.requestPermissions(this, strings, 2)
            }
        }
    }

    private fun getLocationFromService() {
        // Add your API Key in encode
        searchService = SearchServiceFactory.create(this,
            URLEncoder.encode("Add your api_key"))
    }

    override fun onClick(v: View?) {
        val id = v?.id
        if (id == R.id.pickUpLocation) {
            locationBox(100)
        } else if (id == R.id.dropLocation) {
            locationBox(101)
        } else if (id == R.id.customCurrentLocation) {
            getLastLocation()
        }
    }

    private fun locationBox(requestcode: Int) {
        searchIntent = SearchIntent()
        searchIntent!!.setApiKey(URLEncoder.encode("DAEDADRgIFzXbAJpOqImvjRAGRkmm3wGTux0O6JBiaddIPMNTJ4SawIN8ZHWu28dtc1f1H3Cqzh0LC1cgYIvBnl1edWVuWkjciH4NA==", "utf-8"))
        val intent = searchIntent!!.getIntent(this)
        startActivityForResult(intent, requestcode)
    }

    override fun onActivityResult(requestCode: Int, resultCode: Int, @Nullable data: Intent?) {
        super.onActivityResult(requestCode, resultCode, data)
        if (requestCode == 100) {
            if (SearchIntent.isSuccess(resultCode)) {
                isSourceAddressField = true
                val site: Site = searchIntent!!.getSiteFromIntent(data)
                pickUpLocation.setText(site.name)
                querySuggestion()
            }
        }
        if (requestCode == 101) {
            if (SearchIntent.isSuccess(resultCode)) {
                isSourceAddressField = false
                val site: Site = searchIntent!!.getSiteFromIntent(data)
                dropLocation.setText(site.name)
                querySuggestion()
            }
        }
    }

    private fun querySuggestion() {
        val request = QuerySuggestionRequest()
        val query: String?
        if (isSourceAddressField) {
            query = pickUpLocation?.text.toString()
        }else{
            query = dropLocation?.text.toString()
        }
        if (!TextUtils.isEmpty(query)) {
            request.query = query
        }
        searchService?.querySuggestion(
            request,
            searchResultListener as SearchResultListener<QuerySuggestionResponse>?
        )
    }

    private var searchResultListener =
        object : SearchResultListener<QuerySuggestionResponse> {
            override fun onSearchResult(results: QuerySuggestionResponse?) {
                val stringBuilder = StringBuilder()
                results?.let {
                    val sites = results.sites
                    if (sites != null && sites.size > 0) {
                        for (site in sites) {
                            val location = site.location
                            if (isSourceAddressField) {
                                pickupLat = location.lat
                                pickupLng = location.lng
                                moveCamera(LatLng(pickupLat, pickupLng))
                            } else {
                                dropLat = location.lat
                                dropLng = location.lng
                                moveCamera(LatLng(dropLat, dropLng))
                            }
                            break
                        }
                    } else {
                        stringBuilder.append("0 results")
                    }
                }
            }
            override fun onSearchError(status: SearchStatus) {
            }
        }

    private fun getLastLocation() {
        try {
            val lastLocation = mFusedLocationProviderClient.lastLocation
            lastLocation.addOnSuccessListener(OnSuccessListener { location ->
                if (location == null) {
                    return@OnSuccessListener
                }
                moveCamera(LatLng(location.latitude, location.longitude))
                return@OnSuccessListener
            }).addOnFailureListener { e ->
            }
        } catch (e: Exception) {
        }
    }

    private fun moveCamera(latLng: LatLng) {
        hmap!!.moveCamera(CameraUpdateFactory.newLatLngZoom(latLng, 15f))
    }

}
Enter fullscreen mode Exit fullscreen mode

In the activity_search.xml we can create the UI screen.

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    tools:context=".search.SearchActivity">

    <com.huawei.hms.maps.MapView
        android:id="@+id/mapView"
        android:layout_width="match_parent"
        android:layout_height="match_parent">
    </com.huawei.hms.maps.MapView>

    <RelativeLayout
        android:id="@+id/startpoint"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginLeft="42dp"
        android:layout_marginTop="42dp"
        android:layout_marginRight="62dp"
        android:background="@drawable/blue_border_rounded_cornwe">

        <EditText
            android:id="@+id/pickUpLocation"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_toRightOf="@id/start_loc"
            android:background="@android:color/transparent"
            android:hint="Choose starting point "
            android:maxLines="1"
            android:paddingLeft="17dp"
            android:paddingTop="15dp"
            android:paddingBottom="15dp"
            android:textSize="13sp">
        </EditText>
        <ImageView
            android:id="@+id/start_loc"
            android:layout_width="20dp"
            android:layout_height="17dp"
            android:layout_centerVertical="true"
            android:layout_marginLeft="17dp"
            android:src="@drawable/start_icon" />
    </RelativeLayout>

    <RelativeLayout
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginLeft="42dp"
        android:layout_marginTop="23dp"
        android:layout_marginRight="62dp"
        android:layout_below="@+id/startpoint"
        android:background="@drawable/blue_border_rounded_cornwe">
        <EditText
            android:id="@+id/dropLocation"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_toRightOf="@id/dest_loc"
            android:background="@android:color/transparent"
            android:hint="Password"
            android:maxLines="1"
            android:paddingLeft="17dp"
            android:paddingTop="15dp"
            android:paddingBottom="15dp"
            android:textSize="13sp">
        </EditText>
        <ImageView
            android:id="@+id/dest_loc"
            android:layout_width="20dp"
            android:layout_height="17dp"
            android:layout_centerVertical="true"
            android:layout_marginLeft="17dp"
            android:src="@drawable/dest_icon" />
    </RelativeLayout>

    <ImageView
        android:id="@+id/customCurrentLocation"
        android:layout_width="30dp"
        android:layout_height="30dp"
        android:layout_marginRight="10dp"
        android:baselineAlignBottom="true"
        android:layout_centerVertical="true"
        android:layout_centerHorizontal="true"
        android:src="@drawable/location_icon"/>

</RelativeLayout>
Enter fullscreen mode Exit fullscreen mode

Demo

Image description

Tips and Tricks

  1. Make sure you are already registered as Huawei developer.
  2. Set minSDK version to 24 or later, otherwise you will get AndriodManifest merge issue.
  3. Make sure you have added the agconnect-services.json file to app folder.
  4. Make sure you have added SHA-256 fingerprint without fail.
  5. Make sure all the dependencies are added properly.

Conclusion

In this article, we can learn how to search the hospitals located by source and destination address with HMS Core Kits such as Map, Site, and Location Kits. Map kit is to display maps, it covers map data of more than 200 countries and regions for searching any location address. Location kit provides to get the current location and location updates, and it provides flexible location based services globally to the users. Site kit provides with convenient and secure access to diverse, place-related services to users.

I hope you have read this article. If you found it is helpful, please provide likes and comments.

Reference

Map Kit - Documentation

Map KitTraining Video

Location KitDocumentation

Location KitTraining Video

Site Kit

Top comments (0)