Develop Location Based Applications with Huawei Mobile Services — 1

Mustafa Sürücü
Huawei Developers
Published in
6 min readJun 26, 2020

Hi everyone,

This article series aims to support everyone who wants to develop their own location based android application. Let’s start by talking about what we need.

If you want to develop a location based application, it should basically help you to find any location all over the world and provide some features which can support us to access place-related services. Of course, I can hear that you say we need a Map!

HMS Core

Huawei Mobile Services (HMS) is a new whole ecosystem that provides many advanced services and features for developers. We will use and combine HMS Location, Map and Site Kits together to design our demo application.

  • HUAWEI Location Kit combines GPS, Wi-Fi, and base station location data to allow app developers to quickly obtain precise user locations.
  • HUAWEI Map Kit is a set of APIs for map development in Android. It enables map display, interaction and drawing.
  • HUAWEI Site Kit provides some core capabilities to quickly build apps like Place search, Nearby place search, Place details etc.

Note: You should have a Huawei developer account to integrate and use HMS Core capabilities.

Note: To begin with, we should create an Android project and integrate HMS Core capabilities into our project. You can find all required steps from the below link and complete integration easily by following the instructions.

After completing above steps, we can start to activate our target kits in our project. For this purpose, we should add build dependencies into build.gradle file in the app directory.

dependencies {
implementation 'com.huawei.hms:maps:4.0.1.302'
implementation 'com.huawei.hms:location:4.0.4.300'
implementation 'com.huawei.hms:site:4.0.3.300'
}

Note: Please synchronize your project by clicking on “”Sync Now”.

Now, We should apply for some permissions in AndroidManifest.xml to call kit capabilities and obtain current device location.

<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />

We will find our current location via Location Kit and use this information to find nearby places and update map camera position.

//Create Location provider and setting client 
fusedLocationProviderClient = LocationServices.getFusedLocationProviderClient(this);
settingsClient = LocationServices.getSettingsClient(this);
mLocationRequest = new LocationRequest();
mLocationRequest.setInterval(1000000);
mLocationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
setLocation(); //the method where we will use location information

Let’s initialize our map to show our current location and nearby search results. We can start by adding MapView to our layout.

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:map="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<com.huawei.hms.maps.MapView
android:id="@+id/mapView"
android:layout_width="match_parent"
android:layout_height="608dp"
map:cameraTargetLat="51"
map:cameraTargetLng="10"
map:cameraZoom="8.5"
map:mapType="normal"
map:uiCompass="true"
map:uiZoomControls="true" />
</LinearLayout>

Now, we can call MapView with some configurations.

public class MainActivity extends AppCompatActivity  implements OnMapReadyCallback {private static final String TAG = "DemoApplication";
private HuaweiMap hMap;
private MapView mMapView;
private static final String MAPVIEW_BUNDLE_KEY = "MapViewBundleKey";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//Get map instance
mMapView = findViewById(R.id.mapView);
Bundle mapViewBundle = null;
if (savedInstanceState != null) {
mapViewBundle = savedInstanceState.getBundle(MAPVIEW_BUNDLE_KEY);
}
mMapView.onCreate(mapViewBundle);
mMapView.getMapAsync(this);
}
@Override
public void onMapReady(HuaweiMap map) {
hMap = map;
hMap.setMyLocationEnabled(true);
hMap.getUiSettings().setMyLocationButtonEnabled(true);
//call LocationUpdate method and set current location for map instance inside callback.
LocationUpdate();
}

After LocationUpdate method called we will fetch our current location inside Location Callback.

public void setLocation() {
mLocationCallback = new LocationCallback() {
@Override
public void onLocationResult(LocationResult locationResult) {
if (locationResult != null) {
List<Location> locations = locationResult.getLocations();
if (!locations.isEmpty()) {
for (Location location : locations) {
//update camera to your current location
LatLng currentLatLng = new LatLng(location.getLatitude(), location.getLongitude());
CameraUpdate update = CameraUpdateFactory.newLatLngZoom(currentLatLng, 15F);

hMap.moveCamera(update);
}
}
}
}
@Override
public void onLocationAvailability(LocationAvailability locationAvailability) {
if (locationAvailability != null) {
boolean flag = locationAvailability.isLocationAvailable();
Log.i(TAG, "onLocationAvailability isLocationAvailable:" + flag);
}
}
};
}

When we run the application, our map will be initialized and camera will be updated to users’ current location. After this step, we will use Nearby Search function of Site kit to find and show closest places.

Animate Camera to your Location
Animate Camera to Your Location

Note: “API Key” is required to use search service. You can find it in agconnect-services.json file.

//Instantiate searchService and request objects
SearchService
searchService;
NearbySearchRequest request;
try {
searchService = SearchServiceFactory.create(this, URLEncoder.encode("API Key", "utf-8"));
} catch (UnsupportedEncodingException e) {
Log.e(TAG, "encode apikey error");
}
request = new NearbySearchRequest();
request.setRadius(3000);
request.setPageIndex(1);
mSearchText = findViewById(R.id.input_search);

We defined our search request but did not assign any location and poiType for it. The location of request should be set as current location and we will set it inside setLocation() method.

Coordinate myLocation = new Coordinate(locationResult.getLastLocation().getLatitude(), locationResult.getLastLocation().getLongitude());
request.setLocation(myLocation);

For our demo application I would like to arrange poiTypes as closest restaurants, atms, markets and pharmacies by giving the opportunity to choose for end user with buttons. Let’s rearrange our layout for this purpose. You can use below format as reference.

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:map="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">

<RelativeLayout
android:id="@+id/relLayout"
android:layout_width="match_parent"
android:layout_height="48dp"
android:layout_marginLeft="10dp"
android:layout_marginTop="10dp"
android:layout_marginRight="10dp"
android:background="@drawable/shape"
android:elevation="10dp">

<ImageView
android:id="@+id/ic_magnify"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerVertical="true"
android:layout_marginLeft="10dp"
android:contentDescription="TODO"
android:src="@drawable/ic_magnify" />

<EditText
android:id="@+id/input_search"
android:layout_width="339dp"
android:layout_height="match_parent"
android:layout_marginStart="15dp"
android:layout_marginLeft="15dp"
android:layout_toEndOf="@+id/ic_magnify"
android:layout_toRightOf="@+id/ic_magnify"
android:background="@null"
android:hint="Enter your keyword"
android:imeOptions="actionSearch"
android:textColor="#000"
android:textSize="15sp" />

</RelativeLayout>

<com.huawei.hms.maps.MapView
android:id="@+id/mapView"
android:layout_width="match_parent"
android:layout_height="608dp"
map:cameraTargetLat="51"
map:cameraTargetLng="10"
map:cameraZoom="8.5"
map:mapType="normal"
map:uiCompass="true"
map:uiZoomControls="true"></com.huawei.hms.maps.MapView>

<RelativeLayout
android:id="@+id/secondRelLayout"
android:layout_width="match_parent"
android:layout_height="match_parent">


<ImageButton
android:id="@+id/restaurants_nearby"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentStart="true"
android:layout_alignParentBottom="true"
android:layout_marginStart="60dp"
android:layout_marginBottom="15dp"
android:background="@drawable/button_state"
android:onClick="onClick"
android:src="@mipmap/restaurant_45" />

<ImageButton
android:id="@+id/atms_nearby"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_marginStart="40dp"
android:layout_marginBottom="15dp"
android:layout_toEndOf="@id/restaurants_nearby"
android:background="@drawable/button_state"
android:src="@mipmap/atm_45" />

<ImageButton
android:id="@+id/markets_nearby"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_marginStart="40dp"
android:layout_marginBottom="15dp"
android:layout_toEndOf="@id/atms_nearby"
android:background="@drawable/button_state"
android:src="@mipmap/shop_45" />

<ImageButton
android:id="@+id/pharmacy_nearby"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_marginStart="40dp"
android:layout_marginBottom="15dp"
android:layout_toEndOf="@id/markets_nearby"
android:background="@drawable/button_state"
android:foregroundGravity="center"
android:src="@mipmap/pill_45" />

</RelativeLayout>

</LinearLayout>

Now, we should define our buttons and write onClickListener for them. Then, we will specify poiTypes according to user selection and call getNearby() method.

private ImageButton restaurants_button;
private ImageButton atms_button;
private ImageButton markets_button;
private ImageButton pharmacies_button;
restaurants_button = findViewById(R.id.restaurants_nearby);
atms_button = findViewById(R.id.atms_nearby);
markets_button = findViewById(R.id.markets_nearby);
pharmacies_button = findViewById(R.id.pharmacy_nearby);
restaurants_button.setOnClickListener((View.OnClickListener) this);
atms_button.setOnClickListener((View.OnClickListener) this);
markets_button.setOnClickListener((View.OnClickListener) this);
pharmacies_button.setOnClickListener((View.OnClickListener) this);
@Override
public void onClick(View view) {
switch (view.getId()){
case R.id.restaurants_nearby:
type = LocationType.RESTAURANT;
getNearby();
break;
case R.id.atms_nearby:
type = LocationType.ATM;
getNearby();
break;
case R.id.markets_nearby:
type = LocationType.SUPERMARKET;
getNearby();
break;
case R.id.pharmacy_nearby:
type = LocationType.PHARMACY;
getNearby();
break;
}
}

We will fetch the results of nearby search but we want to show places on the map. To do that, we need Array Lists to store targets’ latitude, longitude and names. These lists will be filled with closest places information in accordance with user selection.

ArrayList<Double> targetlat = new ArrayList<Double>();
ArrayList<Double> targetlon = new ArrayList<Double>();
ArrayList<String> targetName = new ArrayList<String>();
public void getNearby(){
request.setPoiType(type);
resultListener = new SearchResultListener<NearbySearchResponse>() {
@Override
public void onSearchResult(NearbySearchResponse results) {
targetlat.clear();
targetlon.clear();
targetName.clear();
List<Site> sites = results.getSites();
if (results == null || results.getTotalCount() <= 0 || sites == null || sites.size() <= 0) {
return;
}
for (Site site : sites) {
Log.i("nearbyme", String.format("siteId: '%s', name: %s\r\n", site.getSiteId(), site.getName()));
targetlat.add(site.getLocation().getLat());
targetlon.add(site.getLocation().getLng());
targetName.add(site.getName());

}
addMarker();
}
@Override
public void onSearchError(SearchStatus status) {
Log.i("TAG", "Error : " + status.getErrorCode() + " " + status.getErrorMessage());
}
};
searchService.nearbySearch(request,resultListener);
}

We got our search result and now all we have to do is showing them on the map. You can add markers and customize them for defined coordinates thanks to HMS Map kit.

public  void addMarker() 
MarkerOptions options = new MarkerOptions();
hMap.clear();
for (int k = 0; k < targetlat.size(); k++) {
options.position(new LatLng(targetlat.get(k), targetlon.get(k)));
options.title(targetName.get(k));
if(type == LocationType.RESTAURANT) { hMap.addMarker(options).setIcon(BitmapDescriptorFactory.fromResource(R.mipmap.restaurant_45));
} else if (type == LocationType.ATM){ hMap.addMarker(options).setIcon(BitmapDescriptorFactory.fromResource(R.mipmap.atm_45));
} else if (type == LocationType.SUPERMARKET) { hMap.addMarker(options).setIcon(BitmapDescriptorFactory.fromResource(R.mipmap.shop_45));
} else if (type == LocationType.PHARMACY) { hMap.addMarker(options).setIcon(BitmapDescriptorFactory.fromResource(R.mipmap.pill_45));
}
}
}
Click any Button and Show Results on Map

I think we made a good progress :) In the next article of this series, we will examine the Direction API of Map Kit and try to discover how to draw polylines for routes.

References

If you need more details about features of HMS kits, you can examine below links.

--

--