HUAWEI Location Kit — Manage Location from single class - Huawei Developers

More information like this, you can visit HUAWEI Developer Forum​
Original link: https://forums.developer.huawei.com/forumPortal/en/topicview?tid=0202351086095380160&fid=0101187876626530001
Location is essential for many apps and developers need services for getting location data. Huawei Location Kit helps developers in enabling their apps to get quick and accurate user locations and expand global positioning capabilities by using GPS, Wi-Fi, and base station locations.
First of all, we have to get a Huawei Developer Account and create a project from Huawei App Gallery Console but since this article is about to Location Kit, we will not cover these topics.
You can refer developer account documentation for creating account, and follow this codelab for creating a project at App Gallery Console.
After enabling Location Kit from Manage API section at console, we need to add Location Kit dependency.
Code:
implementation 'com.huawei.hms:location:5.0.0.301'
After sync project, we are ready to code.
We will cover necessary methods one by one then collect them in a single class for the sake of maintainable and clean code.
First we have to add permissions to our app
Code:
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
If app needs to continuously locate the device when it runs in the background in Android Q, apply for the ACCESS_BACKGROUND_LOCATION
After applying for permissions in the AndroidManifest file, apply for the permissions dynamically in the code (according to requirements for dangerous permissions in Android 6.0).
Code:
if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.P) {
Log.i(TAG, "sdk < 28 Q");
if (ActivityCompat.checkSelfPermission(this,
Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED
|| ActivityCompat.checkSelfPermission(this,
Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
String[] strings =
{Manifest.permission.ACCESS_FINE_LOCATION, Manifest.permission.ACCESS_COARSE_LOCATION};
ActivityCompat.requestPermissions(this, strings, 1);
}
} else {
if (ActivityCompat.checkSelfPermission(this,
Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED
|| ActivityCompat.checkSelfPermission(this,
Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED
|| ActivityCompat.checkSelfPermission(this,
"android.permission.ACCESS_BACKGROUND_LOCATION") != PackageManager.PERMISSION_GRANTED) {
String[] strings = {android.Manifest.permission.ACCESS_FINE_LOCATION,
android.Manifest.permission.ACCESS_COARSE_LOCATION,
"android.permission.ACCESS_BACKGROUND_LOCATION"};
ActivityCompat.requestPermissions(this, strings, 2);
}
}
The location function of Huawei Location Kit depends on the device location settings. If location disabled we can not obtain the device location so it is better to check location setting before obtaining the location.
Check Location Settings
Code:
private val mSettingsClient: SettingsClient by lazy {
LocationServices.getSettingsClient(context)
}
SettingsClient instance allow us to call checkLocationSettings method for obtain to device location settings.
Code:
fun checkLocationSettingsAndShowPopup(
activity: Activity,
onSuccess: ((locationSettingsResponse: LocationSettingsResponse?) -> Unit)? = null
) {
val builder = LocationSettingsRequest.Builder()
val locationRequest = LocationRequest()
builder.addLocationRequest(locationRequest)
val locationSettingsRequest = builder.build()
mSettingsClient.checkLocationSettings(locationSettingsRequest)
.addOnSuccessListener {
// Initiate location requests when the location settings meet the requirements.
LogUtils.d("LocationManager -> Device location is open")
// Notify
onSuccess?.invoke(it)
}
.addOnFailureListener { e ->
// Device location settings do not meet the requirements.
val statusCode = (e as ApiException).statusCode
LogUtils.d("LocationManager -> Device location is close with status code $statusCode, User will get system dialog for enable location")
when (statusCode) {
LocationSettingsStatusCodes.RESOLUTION_REQUIRED -> try {
val rae = e as ResolvableApiException
// Call startResolutionForResult to display a pop-up asking the user to enable related permission.
activity.startIntentSenderForResult(
rae.resolution.intentSender,
REQUEST_CHECK_SETTINGS, null, 0, 0, 0, null
)
} catch (sie: IntentSender.SendIntentException) {
LogUtils.d("LocationKit -> Error while showing system pop-up with error message:" + sie.message)
}
}
}
}
If the location settings do not meet the requirements, we are showing a system dialog for request location permission and catch result in related Activity or Fragment
Code:
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
if (requestCode == REQUEST_CHECK_SETTINGS) {
when (resultCode) {
Activity.RESULT_OK -> {
LogUtils.d("User confirm to access location")
}
Activity.RESULT_CANCELED -> {
LogUtils.d("User denied to access location")
}
}
}
}
After successfully enable device location, we can use location related APIs
Code:
private val mFusedLocationProviderClient: FusedLocationProviderClient by lazy {
LocationServices.getFusedLocationProviderClient(context)
}
We are creating FusedLocationProviderClient instance first. We will use it to call location-related APIs like location availability, last known location, register and unregister location updates.
Location Availability
Code:
fun getLocationAvailability(
onSuccess: ((locationAvailability: LocationAvailability?) -> Unit)? = null,
onFail: ((exception: Exception) -> Unit)? = null
) {
val locationAvailabilityTask: Task<LocationAvailability> = mFusedLocationProviderClient.locationAvailability
locationAvailabilityTask.addOnSuccessListener { locationAvailability ->
if (locationAvailability != null) {
LogUtils.d("Location Kit -> getLocationAvailability onSuccess:${locationAvailability.isLocationAvailable}")
}
// Notify
onSuccess?.invoke(locationAvailability)
}
.addOnFailureListener { e ->
LogUtils.d("getLocationAvailability onFailure:" + e.message)
// Notify
onFail?.invoke(e)
}
}
For obtaining location availability from Huawei Location Services, we call locationAvailability method of FusedLocationProviderClient instance and listen success and failure callbacks.
Last Known Location
Code:
fun getLastKnownLocation(
onSuccess: ((lastKnownLocation: Location?) -> Unit)? = null,
onFail: ((exception: Exception) -> Unit)? = null
) {
val task: Task<Location> = mFusedLocationProviderClient.lastLocation
task.addOnSuccessListener { lastKnowLocation ->
if (lastKnowLocation == null) {
LogUtils.d("LocationKit -> Last Known Location is empty")
} else {
val currentLatLng = LatLng(
lastKnowLocation.latitude,
lastKnowLocation.longitude
)
LogUtils.d("LocationKit -> Last Known Location: $currentLatLng")
}
// Notify
onSuccess?.invoke(lastKnowLocation)
}.addOnFailureListener { exception ->
LogUtils.d("LocationKit -> Failed to get Last Known Location with exception: ${exception.localizedMessage}")
// Notify
onFail?.invoke(exception)
}
}
Just like location availability, we just call lastLocation method of FusedLocationProviderClient instance and listen success and failure callbacks.
If the obtained device location is null, the possible cause is that the system cache has been cleared. In this case, we need to call the requestLocationUpdates method to obtain the device location and update the cache, and then call the lastLocation method to obtain the device location.
Location Updates
Code:
private fun createLocationCallback(
onSuccess: ((location: Location?) -> Unit)? = null,
onFail: ((locationAvailability: LocationAvailability?) -> Unit)? = null
): LocationCallback {
return object : LocationCallback() {
override fun onLocationResult(locationResult: LocationResult) {
val currentLatLng = LatLng(
locationResult.lastLocation.latitude,
locationResult.lastLocation.longitude
)
LogUtils.d("LocationKit -> currentLatLng: $currentLatLng")
// Notify
onSuccess?.invoke(locationResult.lastLocation)
}
override fun onLocationAvailability(locationAvailability: LocationAvailability) {
val flag = locationAvailability.isLocationAvailable
LogUtils.i("LocationKit isLocationAvailable:$flag")
// Notify
onFail?.invoke(locationAvailability)
}
}
}
For request location updates, we have to create a LocationCallback. This callback will be triggered every time when device get new location.
Also we have to specify location request conditions. In order to do that we create a LocationRequest.
Code:
val mLocationRequest = LocationRequest()
// Set the location update interval (in milliseconds).
mLocationRequest.interval = 10000
// Set the weight.
mLocationRequest.priority = LocationRequest.PRIORITY_HIGH_ACCURACY
If we want to obtain location once only we can set numUpdates.
Code:
// Get location update only once
mLocationRequest.numUpdates = 1
Finally we can start listening location updates by calling requestLocationUpdates method of FusedLocationProviderClient.
Code:
fun registerLocationUpdates(
interval: Long = 10000,
onSuccess: ((location: Location?) -> Unit)? = null,
onFail: ((locationAvailability: LocationAvailability?) -> Unit)? = null
) {
val mLocationRequest = LocationRequest()
// Set the location update interval (in milliseconds).
mLocationRequest.interval = interval
// Set the weight.
mLocationRequest.priority = LocationRequest.PRIORITY_HIGH_ACCURACY
// Create location callback
if (mLocationCallback == null)
mLocationCallback = createLocationCallback(onSuccess, onFail)
// Request location update
mFusedLocationProviderClient.requestLocationUpdates(
mLocationRequest,
mLocationCallback,
Looper.getMainLooper()
)
.addOnSuccessListener {
// Requesting location updates is started successfully.
LogUtils.d("LocationKit -> Start Location Updates Successfully")
}
.addOnFailureListener { exception ->
// Failed to start location updates.
LogUtils.d("LocationKit -> Start Location Updates Failed with exception: ${exception.localizedMessage}")
}
}
If app does not need to receive location updates anymore, stop the location update function to reduce power consumption. To do this, call the removeLocationUpdates method, and pass the LocationCallback.
Code:
fun unregisterLocationUpdates() {
mLocationCallback?.let { locationCallback ->
mFusedLocationProviderClient.removeLocationUpdates(locationCallback)
.addOnSuccessListener {
// Requesting location updates is stopped successfully.
LogUtils.d("LocationKit -> Stop Listening Location Successfully")
}
.addOnFailureListener {
// Failed to stop requesting location updates.
LogUtils.d("LocationKit -> Stop Listening Location Failed with exception: ${it.localizedMessage}")
}
}
}
LocationCallback must be same callback that we used at requestLocationUpdates method.
We have covered necessary location related methods, now lets collect them in a single manager class. In this way we can easily separate logic from view and class will be more maintainable
You can see whole class from this gist
In Activity or Fragment, we can easily use this manager class.
Code:
val locationManager = HuaweiLocationManager(this)
locationManager.registerLocationUpdates(onSuccess = {
viewModel.updateCurrentLocation(it)
})
We can see location updates in logcat
{
"lightbox_close": "Close",
"lightbox_next": "Next",
"lightbox_previous": "Previous",
"lightbox_error": "The requested content cannot be loaded. Please try again later.",
"lightbox_start_slideshow": "Start slideshow",
"lightbox_stop_slideshow": "Stop slideshow",
"lightbox_full_screen": "Full screen",
"lightbox_thumbnails": "Thumbnails",
"lightbox_download": "Download",
"lightbox_share": "Share",
"lightbox_zoom": "Zoom",
"lightbox_new_window": "New window",
"lightbox_toggle_sidebar": "Toggle sidebar"
}
Some important key points
Currently, HUAWEI Location Kit can only be used on Huawei phones.
The location permission must be granted to HMS Core (APK). In Android Q, Location must be set to Always for HMS Core (APK).
Min API level should be 19 and EMUI Version should be 5.0 or later
References
https://developer.huawei.com/consumer/en/hms/huawei-locationkit
https://github.com/HMS-Core/hms-location-demo-android-studio
https://github.com/huaweicodelabs/LocationKit

Related

Huawei Cab Application Part-2 – Get Location updates using Map and Site Kit

More information like this, you can visit HUAWEI Developer Forum​
Introduction
Huawei Cab Application is to explore more about HMS Kits in real time scenario, we can use this app as reference to CP during HMS integration, and they can understand easily how HMS works in real time scenario, refer previous article.
Dashboard Module
The Dashboard page allows a user to book a cab with help of Huawei location, map and site kits, as follows:
Location kit provides to get the current location and location updates, and it provides flexible location based services globally to the users.
Huawei Map kit is to display maps, it covers map data of more than 200 countries and regions for searching any location address.
Site kit provides with convenient and secure access to diverse, place-related services to users.
Kits covered in Dashboard Module:
1. Location kit
2. Map kit
3. Site kit
4. Ads kit
Third Party API’s:
1. TomTom for Directions API
App Screenshots:
Auto fetch current location and also customize current location button in huawei map.
{
"lightbox_close": "Close",
"lightbox_next": "Next",
"lightbox_previous": "Previous",
"lightbox_error": "The requested content cannot be loaded. Please try again later.",
"lightbox_start_slideshow": "Start slideshow",
"lightbox_stop_slideshow": "Stop slideshow",
"lightbox_full_screen": "Full screen",
"lightbox_thumbnails": "Thumbnails",
"lightbox_download": "Download",
"lightbox_share": "Share",
"lightbox_zoom": "Zoom",
"lightbox_new_window": "New window",
"lightbox_toggle_sidebar": "Toggle sidebar"
}
Pick destination you want to travel with marker in the huawei map view.
Pick destination using HMS Site Kit.
Draw route between start and end location.
Huawei Location Kit
HUAWEI Location Kit combines the GPS, Wi-Fi, and base station location functionalities in your app to build up global positioning capabilities, allowing you 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 needed.
Huawei Map Kit
The HMS Core Map SDK is a set of APIs for map development in Android. The map data covers most countries outside China and supports multiple languages. The Map SDK uses the WGS 84 GPS coordinate system, which can meet most requirements of map development outside China. You can easily add map-related functions in your Android app, including:
Map display: Displays buildings, roads, water systems, and Points of Interest (POIs).
Map interaction: Controls the interaction gestures and buttons on the map.
Map drawing: Adds location markers, map layers, overlays, and various shapes.
Site Kit
HUAWEI Site Kit provide to users with convenient and secure access to diverse, place-related services.
Ads Kit
Huawei Ads provide developers extensive data capabilities to deliver high quality ad content to users. By integrating HMS ads kit we can start earning right away. It is very useful particularly when we are publishing a free app and want to earn some money from it.
Integrating HMS ads kit does not take more than 10 minuts HMS ads kit currently offers five types of ad format like Banner, Native, Rewarded, Interstitial and Splash ads.
In this article, we will see banner ad also.
Banner Ad: Banner ads are rectangular images that occupy a spot at the top, middle, or bottom within an app's layout. Banner ads refresh automatically at regular intervals. When a user taps a banner ad, the user is redirected to the advertiser's page in most cases.
TomTom for Direction API
TomTom Technology for a moving world. Meet the leading independent location, navigation and map technology specialist.
Follow the steps for TomTom Direction API.
Step1: Visit TomTom Developer Portal. https://developer.tomtom.com/
Step2: Login/Signup.
Step3: Click PRODUCTS and select Directions API
Step 4: Route API, as follows: https://developer.tomtom.com/routing-api/routing-api-documentation-routing/calculate-route
Step5: Click MY DASHBOARD and Copy Key and Use it in your application.
Integration Preparations
To integrate HUAWEI Map, Site, Location and Ads Kit, you must complete the following preparations:
Create an app in AppGallery Connect.
Create a project in Android Studio.
Generate a signing certificate.
Generate a signing certificate fingerprint.
Configure the signing certificate fingerprint.
Add the app package name and save the configuration file.
Add the AppGallery Connect plug-in and the Maven repository in the project-level build.gradle file.
Configure the signature file in Android Studio.
Configuring the Development Environment
Enabling HUAWEI Map, Site, Location and Ads Kit.
1. Sign in to AppGallery Connect, select My apps, click an app, and navigate to Develop > Overview > Manage APIs.
2. Click agconnect-services.json to download the configuration file.
3. Copy the agconnect-services.json file to the app's root directory.
4. Open the build.gradle file in the root directory of your Android Studio project.
5. Configure the following information in the build.gradle file.
Code:
buildscript {
repositories {
google()
jcenter()
maven {url 'https://developer.huawei.com/repo/'}
}
dependencies {
classpath 'com.huawei.agconnect:agcp:1.3.2.301'
}
}
allprojects {
repositories {
google()
jcenter()
maven {url 'https://developer.huawei.com/repo/'}
}
}
6. Open the build.gradle file in the app directory.
7. Add Dependencies in app level build.gradle.
Code:
apply plugin: 'com.huawei.agconnect'dependencies {
implementation 'com.huawei.hms:maps:5.0.1.300'
implementation 'com.huawei.hms:location:5.0.0.302'
implementation 'com.huawei.hms:site:5.0.0.300'
implementation 'com.huawei.hms:ads-lite:13.4.30.307'
}
8. Apply for relevant permissions in sections at the same level as the application section in the AndroidManifest.xml file.
Code:
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
9. Add Huawei MapView and Banner Ad in layout file: activity_maview.xml
Code:
<!--MapView-->
<com.huawei.hms.maps.MapView
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/mapview"
android:layout_width="match_parent"
android:layout_height="match_parent"
map:cameraTargetLat="51"
map:cameraTargetLng="10"
map:cameraZoom="8.5"
map:mapType="normal"
map:uiCompass="true"
map:uiZoomControls="true" />
<!--BannerView-->
<com.huawei.hms.ads.banner.BannerView
android:id="@+id/hw_banner_view"
android:layout_width="match_parent"
android:layout_height="wrap_content"
hwads:adId="@string/banner_ad_id"
android:layout_alignParentTop="true"
hwads:bannerSize="BANNER_SIZE_360_57" />
10. Add the configuration for calling the MapView to the activity.
Code:
class DashboardFragment : Fragment(), OnMapReadyCallback, ReverseGeoCodeListener {private var hMap: HuaweiMap? = null
private var mMapView: MapView? = null
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 mPolyline: Polyline? = null
private var mMarkerDestination: Marker? = nulloverride fun onActivityCreated(savedInstanceState: Bundle?) {
super.onActivityCreated(savedInstanceState) // create fusedLocationProviderClient
mFusedLocationProviderClient = LocationServices.getFusedLocation ProviderClient(activity) mapView?.onCreate(savedInstanceState)
mapView?.onResume()
mapView?.getMapAsync(this)}
fun initBannerAds() {
// Obtain BannerView based on the configuration in layout.
val adParam: AdParam = AdParam.Builder().build()
hw_banner_view.loadAd(adParam)
}
override fun onMapReady(map: HuaweiMap) {
Log.d(TAG, "onMapReady: ")
hMap = map hMap?.isMyLocationEnabled = true
hMap?.uiSettings?.isMyLocationButtonEnabled = false
getLastLocation()
hMap?.setOnCameraMoveStartedListener {
when (it) {
HuaweiMap.OnCameraMoveStartedListener.REASON_GESTURE -> {
Log.d(TAG, "The user gestured on the map.")
val midLatLng: LatLng = hMap?.cameraPosition!!.target
Log.d("Moving_LatLng ", "" + midLatLng)
dropLat = midLatLng.latitude
dropLng = midLatLng.longitude
val task = MyAsyncTask(this, false)
task.execute(midLatLng.latitude, midLatLng.longitude) }
HuaweiMap.OnCameraMoveStartedListener
.REASON_API_ANIMATION -> {
Log.d(TAG, "The user tapped something on the map.")
}
HuaweiMap.OnCameraMoveStartedListener
.REASON_DEVELOPER_ANIMATION -> {
Log.d(TAG, "The app moved the camera.")
}
}
}
}
11. Add the life cycle method of the MapView
Code:
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()
}
override fun onLowMemory() {
super.onLowMemory()
mMapView?.onLowMemory()
}
12. Check permissions to let the user allow App to access user location from android 6.0
Code:
if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.P) {
Log.i(TAG, "sdk < 28 Q")
if (checkSelfPermission(
this,
ACCESS_FINE_LOCATION
) != PERMISSION_GRANTED && checkSelfPermission(
this,
ACCESS_COARSE_LOCATION
) != PERMISSION_GRANTED
) {
val strings = arrayOf(ACCESS_FINE_LOCATION, ACCESS_COARSE_LOCATION)
requestPermissions(this, strings, 1)
}
} else {
if (checkSelfPermission(
[email protected],
ACCESS_FINE_LOCATION
) != PERMISSION_GRANTED && checkSelfPermission(
[email protected], ACCESS_COARSE_LOCATION
) != PERMISSION_GRANTED && checkSelfPermission(
[email protected],
"android.permission.ACCESS_BACKGROUND_LOCATION"
) != PERMISSION_GRANTED
) {
val strings = arrayOf(
ACCESS_FINE_LOCATION,
ACCESS_COARSE_LOCATION,
"android.permission.ACCESS_BACKGROUND_LOCATION"
)
requestPermissions(this, strings, 2)
}
}
13. In you activity you need to handle the response by this way.
Code:
Array<String>, grantResults: IntArray) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults)
if (requestCode == 1) {
if (grantResults.size > 1 && grantResults[0] == PERMISSION_GRANTED && grantResults[1] == PERMISSION_GRANTED) {
Log.i(TAG, "onRequestPermissionsResult: apply LOCATION PERMISSION successful")
} else {
Log.i(TAG, "onRequestPermissionsResult: apply LOCATION PERMISSSION failed")
}
}
if (requestCode == 2) {
if (grantResults.size > 2 && grantResults[2] == PERMISSION_GRANTED && grantResults[0] == PERMISSION_GRANTED && grantResults[1] == PERMISSION_GRANTED) { override fun onRequestPermissionsResult(requestCode: Int, permissions: Log.i(TAG, "onRequestPermissionsResult: apply ACCESS_BACKGROUND_LOCATION successful")
} else {
Log.i(TAG, "onRequestPermissionsResult: apply ACCESS_BACKGROUND_LOCATION failed")
}
}
}
You can perform subsequent steps by referring to the RequestLocationUpdatesWithCallbackActivity.kt file.
14. Create a location provider client and device setting client.
Code:
// create fusedLocationProviderClient
fusedLocationProviderClient=LocationServices.getFusedLocationProviderClient(this)
// create settingsClient
settingsClient = LocationServices.getSettingsClient(this)
15. Create a location request.
Code:
mLocationRequest = LocationRequest().apply {
// set the interval for location updates, in milliseconds
interval = 1000
needAddress = true
// set the priority of the request
priority = LocationRequest.PRIORITY_HIGH_ACCURACY
}
16. Create a result callback.
Code:
mLocationCallback = object : LocationCallback() {
override fun onLocationResult(locationResult: LocationResult?) {
if (locationResult != null) {
val locations: List<Location> =
locationResult.locations
if (locations.isNotEmpty()) {
for (location in locations) {
LocationLog.i(TAG,"onLocationResult location[Longitude,Latitude,Accuracy]:${location.longitude} , ${location.latitude} , ${location.accuracy}")
}
}
}
}
override fun onLocationAvailability(locationAvailability: LocationAvailability?) {
locationAvailability?.let {
val flag: Boolean = locationAvailability.isLocationAvailable
LocationLog.i(TAG, "onLocationAvailability isLocationAvailable:$flag")
}
}
}
17. Request location updates.
Code:
private fun requestLocationUpdatesWithCallback() {
try {
val builder = LocationSettingsRequest.Builder()
builder.addLocationRequest(mLocationRequest)
val locationSettingsRequest = builder.build()
// check devices settings before request location updates.
//Before requesting location update, invoke checkLocationSettings to check device settings.
val locationSettingsResponseTask: Task<LocationSettingsResponse> = settingsClient.checkLocationSettings(locationSettingsRequest)
locationSettingsResponseTask.addOnSuccessListener { locationSettingsResponse: LocationSettingsResponse? ->
Log.i(TAG, "check location settings success {$locationSettingsResponse}")
// request location updates
fusedLocationProviderClient.requestLocationUpdates(mLocationRequest, mLocationCallback, Looper.getMainLooper())
.addOnSuccessListener {
LocationLog.i(TAG, "requestLocationUpdatesWithCallback onSuccess")
}
.addOnFailureListener { e ->
LocationLog.e(TAG, "requestLocationUpdatesWithCallback onFailure:${e.message}")
}
}
.addOnFailureListener { e: Exception ->
LocationLog.e(TAG, "checkLocationSetting onFailure:${e.message}")
when ((e as ApiException).statusCode) {
LocationSettingsStatusCodes.RESOLUTION_REQUIRED -> try {
val rae = e as ResolvableApiException
rae.startResolutionForResult(
[email protected]uestLocationUpdatesWithCallbackActivity, 0
)
} catch (sie: SendIntentException) {
Log.e(TAG, "PendingIntent unable to execute request.")
}
}
}
} catch (e: Exception) {
LocationLog.e(TAG, "requestLocationUpdatesWithCallback exception:${e.message}")
}
}
18. Remove location updates.
Code:
private fun removeLocationUpdatesWithCallback() {
try {
fusedLocationProviderClient.removeLocationUpdates(mLocationCallback)
.addOnSuccessListener {
LocationLog.i(
TAG,
"removeLocationUpdatesWithCallback onSuccess"
)
}
.addOnFailureListener { e ->
LocationLog.e(
TAG,
"removeLocationUpdatesWithCallback onFailure:${e.message}"
)
}
} catch (e: Exception) {
LocationLog.e(
TAG,
"removeLocationUpdatesWithCallback exception:${e.message}"
)
}
}
19. Reverse Geocoding
Code:
companion object {
private const val TAG = "MapViewDemoActivity"
private const val MAPVIEW_BUNDLE_KEY = "MapViewBundleKey"
class MyAsyncTask internal constructor(
private val context: DashboardFragment,
private val isStartPos: Boolean
) : AsyncTask<Double, Double, String?>() {
private var resp: String? = null
lateinit var geocoding: Geocoding
override fun onPreExecute() {
}
override fun doInBackground(vararg params: Double?): String? {
try {
geocoding = Geocoding()
geocoding.reverseGeoCodeListener = context
geocoding.reverseGeocoding(
"reverseGeocode",
"YOUR_API_KEY",
params[0],
params[1],
isStartPos
)
} catch (e: InterruptedException) {
e.printStackTrace()
} catch (e: Exception) {
e.printStackTrace()
}
return resp
} override fun onPostExecute(result: String?) {
}
override fun onProgressUpdate(vararg values: Double?) {
}
}
}
20. Geocoding class for converting latlng into Address
Code:
class Geocoding {
var reverseGeoCodeListener: ReverseGeoCodeListener? = null
val ROOT_URL = "https://siteapi.cloud.huawei.com/mapApi/v1/siteService/"
val conection =
"?key="
val JSON = MediaType.parse("application/json; charset=utf-8")
open fun reverseGeocoding(serviceName: String, apiKey: String?, lat: Double?, lng: Double?, isStartPos: Boolean) {
var sites: String = ""
val json = JSONObject()
val location = JSONObject()
try {
location.put("lng", lng)
location.put("lat", lat)
json.put("location", location)
json.put("language", "en")
json.put("politicalView", "CN")
json.put("returnPoi", true)
Log.d("MapViewDemoActivity",json.toString())
} catch (e: JSONException) {
Log.e("error", e.message)
}
val body : RequestBody = RequestBody.create(JSON, json.toString())
val client = OkHttpClient()
val request = Request.Builder()
.url(ROOT_URL + serviceName + conection + URLEncoder.encode(apiKey, "UTF-8"))
.post(body)
.build()
client.newCall(request).enqueue(object : Callback {
@Throws(IOException::class)
override fun onResponse(call: Call, response: Response) {
var str_response = response.body()!!.string()
val json_response:JSONObject = JSONObject(str_response)
val responseCode:String = json_response.getString("returnCode")
if (responseCode.contentEquals("0")) {
Log.d("ReverseGeocoding", str_response)
var jsonarray_sites: JSONArray = json_response.getJSONArray("sites")
var i:Int = 0
var size:Int = jsonarray_sites.length()
var json_objectdetail:JSONObject=jsonarray_sites.getJSONObject(0)
sites = json_objectdetail.getString("formatAddress")
Log.d("formatAddress", sites)
reverseGeoCodeListener?.getAddress(sites, isStartPos)
} else{
sites = "No Result"
Log.d("formatAddress", "")
reverseGeoCodeListener?.onAdddressError(sites)
}
}
override fun onFailure(call: Call, e: IOException) {
sites = "No Result"
Log.e("ReverseGeocoding", e.toString())
reverseGeoCodeListener?.onAdddressError(sites)
}
})
}
}
This is not the end. For full content, you can visit https://forums.developer.huawei.com/forumPortal/en/topicview?tid=0201352135916100198&fid=0101187876626530001
When am integrating site getting error code 6? can you explain why
sujith.e said:
When am integrating site getting error code 6? can you explain why
Click to expand...
Click to collapse
Hi, Sujith.e. The possible cause is that the API key contains special characters. You need to encode the special characters using encodeURI.

How to Integrate HUAWEI Drive Kit

More information like this, you can visit HUAWEI Developer Forum​
Hello everyone, in this article we will create an Android application using the capabilities of HUAWEI Drive Kit that will allow users to manage and edit files in HUAWEI Drive, as well as store photos, drawings, designs, recordings and videos.
Why should we use HUAWEI Drive Kit?
With HUAWEI Drive Kit, you can let your users store data on the cloud quick and easy. Users can upload, download, synchronize, and view images, videos, and documents whenever and wherever they want.
There are 3 main functions provided by HUAWEI Drive Kit.
User file management: Includes file search, comment, and reply in addition to basic functions.
App data management: Supports app data storage and restoration.
Cross-platform capability: Provides RESTful APIs to support app access from non-Android devices.
Integration Preparations
Before you get started, you must first register as a HUAWEI developer and verify your identity on the HUAWEI Developer website. For more details, please refer to Register a HUAWEI ID.
Software Requirements
Java JDK installation package
Android SDK package
Android Studio 3.X
HMS Core (APK) 3.X or later
Supported Locations
To see all supported locations, please refer to HUAWEI Drive Kit Supported Locations
Integrating HMS Core SDK
To integrate HMS Core SDK in your application and learn creating a new project on AppGallery Connect, follow this great guide: https://medium.com/huawei-developers/android-integrating-your-apps-with-huawei-hms-core-1f1e2a090e98
Keep in mind: Users need to sign in with their HUAWEI ID before they can use the functions provided by HUAWEI Drive Kit. If the user has not signed in with a HUAWEI ID, the HMS Core SDK will prompt the user to sign in first.
Implementation
Code:
implementation 'com.huawei.hms:drive:5.0.0.301'
implementation 'com.huawei.hms:hwid:5.0.1.301'
Now that we’re ready to implement our methods, let’s see how they work.
Signing In with a HUAWEI ID
To implement the sign-in function through the HMS Core SDK, you will need to set the Drive scope for obtaining the permission to access Drive APIs.
Each Drive scope corresponds to a certain type of permissions. You may apply for the permissions as needed. For details about the corresponding APIs, please refer to HUAWEI Account Kit Development Guide.
Code:
private void driveSignIn() {
List<Scope> scopeList = new ArrayList<>();
scopeList.add(new Scope(DriveScopes.SCOPE_DRIVE));
scopeList.add(new Scope(DriveScopes.SCOPE_DRIVE_APPDATA));
scopeList.add(new Scope(DriveScopes.SCOPE_DRIVE_FILE));
scopeList.add(new Scope(DriveScopes.SCOPE_DRIVE_METADATA));
scopeList.add(new Scope(DriveScopes.SCOPE_DRIVE_METADATA_READONLY));
scopeList.add(new Scope(DriveScopes.SCOPE_DRIVE_READONLY));
scopeList.add(HuaweiIdAuthAPIManager.HUAWEIID_BASE_SCOPE);
HuaweiIdAuthParams authParams = new HuaweiIdAuthParamsHelper(HuaweiIdAuthParams.DEFAULT_AUTH_REQUEST_PARAM)
.setAccessToken()
.setIdToken()
.setScopeList(scopeList)
.createParams();
HuaweiIdAuthService authService = HuaweiIdAuthManager.getService(this, authParams);
startActivityForResult(authService.getSignInIntent(), REQUEST_SIGN_IN_LOGIN);
}
@Override
protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (requestCode == REQUEST_SIGN_IN_LOGIN) {
Task<AuthHuaweiId> authHuaweiIdTask = HuaweiIdAuthManager.parseAuthResultFromIntent(data);
if (authHuaweiIdTask.isSuccessful()) {
AuthHuaweiId authHuaweiId = authHuaweiIdTask.getResult();
mAccessToken = authHuaweiId.getAccessToken();
mUnionId = authHuaweiId.getUnionId();
int returnCode = init(mUnionId, mAccessToken, refreshAccessToken);
if (returnCode == DriveCode.SUCCESS) {
Log.d(TAG, "onActivityResult: driveSignIn success");
} else {
Log.d(TAG, "onActivityResult: driveSignIn failed");
}
} else {
Log.d(TAG, "onActivityResult, signIn failed: " + ((ApiException) authHuaweiIdTask.getException()).getStatusCode());
}
}
}
Handling the Permissions
Add the read and write permissions for the phone storage to AndroidManifest.xml
Code:
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission
android:name="android.permission.WRITE_MEDIA_STORAGE"
tools:ignore="ProtectedPermissions" />
Add the permissions to request in MainActivity.java.
Code:
private static String[] PERMISSIONS_STORAGE = {
Manifest.permission.READ_EXTERNAL_STORAGE,
Manifest.permission.WRITE_EXTERNAL_STORAGE,
Manifest.permission.CAMERA
};
Request the permissions in the onCreate method.
Code:
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
requestPermissions(PERMISSIONS_STORAGE, 1);
}
Create a Folder and Upload a File
Now that we handled necessary permissions, let’s upload some files!
Create a folder in the root directory of Drive, and upload the file in the designated directory.
Keep in mind: the code below contains global variables and functions, you can download the sample code from the link at the end of the article to view their meanings.
Code:
private void uploadFiles() {
new Thread(new Runnable() {
@Override
public void run() {
try {
if (mAccessToken == null) {
Log.d(TAG, "need to sign in first");
return;
}
if (StringUtils.isNullOrEmpty(et_uploadFileName.getText().toString())) {
Log.d(TAG, "file name is required to upload");
return;
}
String path = getExternalFilesDir(null).getAbsolutePath()
+ "/" + et_uploadFileName.getText();
Log.d(TAG, "run: " + path);
java.io.File fileObj = new java.io.File(path);
if (!fileObj.exists()) {
Log.d(TAG, "file does not exists");
return;
}
Drive drive = buildDrive();
Map<String, String> appProperties = new HashMap<>();
appProperties.put("appProperties", "property");
String dirName = "Uploads";
File file = new File();
file.setFileName(dirName)
.setAppSettings(appProperties)
.setMimeType("application/vnd.huawei-apps.folder");
directoryCreated = drive.files().create(file).execute();
// Upload the file
File fileToUpload = new File()
.setFileName(fileObj.getName())
.setMimeType(mimeType(fileObj))
.setParentFolder(Collections.singletonList(directoryCreated.getId()));
Drive.Files.Create request = drive.files()
.create(fileToUpload, new FileContent(mimeType(fileObj), fileObj));
fileUploaded = request.execute();
Log.d(TAG, "upload success");
} catch (Exception e) {
Log.d(TAG, "upload error " + e.toString());
}
}
}).start();
}
If applicationData is selected, the operation will be performed on the app data folder. The app data folder is invisible to users and is used to store app-specific data.
After the upload is done, the users can view the file by going to Files > HUAWEI Drive.
{
"lightbox_close": "Close",
"lightbox_next": "Next",
"lightbox_previous": "Previous",
"lightbox_error": "The requested content cannot be loaded. Please try again later.",
"lightbox_start_slideshow": "Start slideshow",
"lightbox_stop_slideshow": "Stop slideshow",
"lightbox_full_screen": "Full screen",
"lightbox_thumbnails": "Thumbnails",
"lightbox_download": "Download",
"lightbox_share": "Share",
"lightbox_zoom": "Zoom",
"lightbox_new_window": "New window",
"lightbox_toggle_sidebar": "Toggle sidebar"
}
Query File Details
With this method we can get the details of a file in Drive. Below, we get the id, file name and size information.
Code:
private void queryFiles() {
new Thread(new Runnable() {
@Override
public void run() {
try {
if (mAccessToken == null) {
Log.d(TAG, "need to sign in first");
return;
}
String containers = "";
String queryFile = "fileName = '" + et_searchFileName.getText()
+ "' and mimeType != 'application/vnd.huawei-apps.folder'";
if (cb_isApplicationData.isChecked()) {
containers = "applicationData";
queryFile = "'applicationData' in parentFolder and ".concat(queryFile);
}
Drive drive = buildDrive();
Drive.Files.List request = drive.files().list();
FileList files;
while (true) {
files = request
.setQueryParam(queryFile)
.setPageSize(10)
.setOrderBy("fileName")
.setFields("category,nextCursor,files(id,fileName,size)")
.setContainers(containers)
.execute();
if (files == null || files.getFiles().size() > 0) {
break;
}
if (!StringUtils.isNullOrEmpty(files.getNextCursor())) {
request.setCursor(files.getNextCursor());
} else {
break;
}
}
String text = "";
if (files != null && files.getFiles().size() > 0) {
fileSearched = files.getFiles().get(0);
text = fileSearched.toString();
} else {
text = "empty";
}
final String finalText = text;
MainActivity.this.runOnUiThread(new Runnable() {
@Override
public void run() {
tv_queryResult.setText(finalText);
}
});
Log.d(TAG, "query success");
} catch (Exception e) {
Log.d(TAG, "query error " + e.toString());
}
}
}).start();
}
Download Files
We can also download files from Drive. Just query the file (notice the fileSearched global variable above) and download with Drive.Files.Get request.
This is not the end. For full content, you can visit https://forums.developer.huawei.com/forumPortal/en/topicview?tid=0202357120930420217&fid=0101187876626530001
Is there any restriction on type of files which can be uploaded and while uploading are there any security measures taken like encryption of my data ?
Nice and useful article
DOes Huawei drive kit work in India?

Search News with Voice (Search Kit — ML Kit(ASR)— Network Kit)

{
"lightbox_close": "Close",
"lightbox_next": "Next",
"lightbox_previous": "Previous",
"lightbox_error": "The requested content cannot be loaded. Please try again later.",
"lightbox_start_slideshow": "Start slideshow",
"lightbox_stop_slideshow": "Stop slideshow",
"lightbox_full_screen": "Full screen",
"lightbox_thumbnails": "Thumbnails",
"lightbox_download": "Download",
"lightbox_share": "Share",
"lightbox_zoom": "Zoom",
"lightbox_new_window": "New window",
"lightbox_toggle_sidebar": "Toggle sidebar"
}
Hello everyone. In this article, I will try to talk about the uses of Huawei Search Kit, Huawei ML Kit and Huawei Network Kit. I have developed a demo app using these 3 kits to make it clearer.
What is Search Kit?​HUAWEI Search Kit fully opens Petal Search capabilities through the device-side SDK and cloud-side APIs, enabling ecosystem partners to quickly provide the optimal mobile app search experience.
What is Network Kit?​Network Kit is a basic network service suite. It incorporates Huawei’s experience in far-field network communications, and utilizes scenario-based RESTful APIs as well as file upload and download APIs. Therefore, Network Kit can provide you with easy-to-use device-cloud transmission channels featuring low latency, high throughput, and high security.
What is ML Kit — ASR?​Automatic speech recognition (ASR) can recognize speech not longer than 60s and convert the input speech into text in real time. This service uses industry-leading deep learning technologies to achieve a recognition accuracy of over 95%.
Development Steps​1. Integration
First of all, we need to create an app on AppGallery Connect and add related details about HMS Core to our project. You can access the article about that steps from the link below.
Android | Integrating Your Apps With Huawei HMS Core
Hi, this article explains you how to integrate with HMS (Huawei Mobile Services) and making AppGallery Connect Console project settings.
medium.com
2. Adding Dependencies
After HMS Core is integrated into the project and the Search Kit and ML Kit are activated through the console, the required library should added to the build.gradle file in the app directory as follows. The project’s minSdkVersion value should be 24. For this, the minSdkVersion value in the same file should be updated to 24.
Java:
...
defaultConfig {
applicationId "com.myapps.searchappwithml"
minSdkVersion 24
targetSdkVersion 30
versionCode 1
versionName "1.0"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
}
...
dependencies {
...
implementation 'com.huawei.agconnect:agconnect-core:1.5.0.300'
implementation 'com.huawei.hms:network-embedded:5.0.1.301'
implementation 'com.huawei.hms:searchkit:5.0.4.303'
implementation 'com.huawei.hms:ml-computer-voice-asr-plugin:2.2.0.300'
...
}
3. Adding Permissions
Java:
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.RECORD_AUDIO" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
4. Application Class
When the application is started, we need to initialize the Kits in the Application class. Then we need to specify the Application class to the “android: name” tag in the manifest file.
Java:
@HiltAndroidApp
class SearchApplication : Application(){
override fun onCreate() {
super.onCreate()
initNetworkKit()
initSearchKit()
initMLKit()
}
private fun initNetworkKit(){
NetworkKit.init(
applicationContext,
object : NetworkKit.Callback() {
override fun onResult(result: Boolean) {
if (result) {
Log.i(NETWORK_KIT_TAG, "init success")
} else {
Log.i(NETWORK_KIT_TAG, "init failed")
}
}
})
}
private fun initSearchKit(){
SearchKitInstance.init(this, APP_ID)
CoroutineScope(Dispatchers.IO).launch {
SearchKitInstance.instance.refreshToken()
}
}
private fun initMLKit() {
MLApplication.getInstance().apiKey = API_KEY
}
}
5. Getting Access Token
We need to use Access Token to send requests to Search Kit. I used the Network Kit to request the Access Token. Its use is very similar to services that perform other Network operations.
As with other Network Services, there are Annotations such as POST, FormUrlEncoded, Headers, Field.
Java:
interface AccessTokenService {
@POST("oauth2/v3/token")
@FormUrlEncoded
@Headers("Content-Type:application/x-www-form-urlencoded", "charset:UTF-8")
fun createAccessToken(
@Field("grant_type") grant_type: String,
@Field("client_secret") client_secret: String,
@Field("client_id") client_id: String
) : Submit<String>
}
We need to create our request structure using the RestClient class.
Java:
@Module
@InstallIn(ApplicationComponent::class)
class ApplicationModule {
companion object{
private const val TIMEOUT: Int = 500000
private var restClient: RestClient? = null
fun getClient() : RestClient {
val httpClient = HttpClient.Builder()
.connectTimeout(TIMEOUT)
.writeTimeout(TIMEOUT)
.readTimeout(TIMEOUT)
.build()
if (restClient == null) {
restClient = RestClient.Builder()
.baseUrl("https://oauth-login.cloud.huawei.com/")
.httpClient(httpClient)
.build()
}
return restClient!!
}
}
}
Finally, by sending the request, we reach the AccessToken.
Java:
data class AccessTokenModel (
var access_token : String,
var expires_in : Int,
var token_type : String
)
...
fun SearchKitInstance.refreshToken() {
ApplicationModule.getClient().create(AccessTokenService::class.java)
.createAccessToken(
GRANT_TYPE,
CLIENT_SECRET,
CLIENT_ID
)
.enqueue(object : Callback<String>() {
override fun onFailure(call: Submit<String>, t: Throwable) {
Log.d(ACCESS_TOKEN_TAG, "getAccessTokenErr " + t.message)
}
override fun onResponse(
call: Submit<String>,
response: Response<String>
) {
val convertedResponse =
Gson().fromJson(response.body, AccessTokenModel::class.java)
setInstanceCredential(convertedResponse.access_token)
}
})
}
6. ML Kit (ASR) — Search Kit
Since we are using ML Kit (ASR), we first need to get microphone permission from the user. Then we start ML Kit (ASR) with the help of a button and get a text from the user. By sending this text to the function we created for the Search Kit, we reach the data we will show on the screen.
Here I used the Search Kit’s Web search feature. Of course, News, Image, Video search features can be used according to need.
Java:
@AndroidEntryPoint
class MainActivity : AppCompatActivity() {
private lateinit var binding: MainBinding
private val adapter: ResultAdapter = ResultAdapter()
private var isPermissionGranted: Boolean = false
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = MainBinding.inflate(layoutInflater)
setContentView(binding.root)
binding.button.setOnClickListener {
if (isPermissionGranted) {
startASR()
}
}
binding.recycler.adapter = adapter
val permission = arrayOf(Manifest.permission.INTERNET, Manifest.permission.RECORD_AUDIO)
ActivityCompat.requestPermissions(this, permission,MIC_PERMISSION)
}
override fun onRequestPermissionsResult(
requestCode: Int,
permissions: Array<out String>,
grantResults: IntArray
) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults)
when (requestCode) {
MIC_PERMISSION -> {
// If request is cancelled, the result arrays are empty.
if (grantResults.isNotEmpty()
&& grantResults[0] == PackageManager.PERMISSION_GRANTED
&& grantResults[1] == PackageManager.PERMISSION_GRANTED) {
// permission was granted
Toast.makeText(this, "Permission granted", Toast.LENGTH_SHORT).show()
isPermissionGranted = true
} else {
// permission denied,
Toast.makeText(this, "Permission denied", Toast.LENGTH_SHORT).show()
}
return
}
}
}
private fun startASR() {
val intent = Intent(this, MLAsrCaptureActivity::class.java)
.putExtra(MLAsrCaptureConstants.LANGUAGE, "en-US")
.putExtra(MLAsrCaptureConstants.FEATURE, MLAsrCaptureConstants.FEATURE_WORDFLUX)
startActivityForResult(intent, ASR_REQUEST_CODE)
}
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
if (requestCode == ASR_REQUEST_CODE) {
when (resultCode) {
MLAsrCaptureConstants.ASR_SUCCESS -> if (data != null) {
val bundle = data.extras
if (bundle != null && bundle.containsKey(MLAsrCaptureConstants.ASR_RESULT)) {
val text = bundle.getString(MLAsrCaptureConstants.ASR_RESULT).toString()
performSearch(text)
}
}
MLAsrCaptureConstants.ASR_FAILURE -> if (data != null) {
val bundle = data.extras
if (bundle != null && bundle.containsKey(MLAsrCaptureConstants.ASR_ERROR_CODE)) {
val errorCode = bundle.getInt(MLAsrCaptureConstants.ASR_ERROR_CODE)
Toast.makeText(this, "Error Code $errorCode", Toast.LENGTH_LONG).show()
}
if (bundle != null && bundle.containsKey(MLAsrCaptureConstants.ASR_ERROR_MESSAGE)) {
val errorMsg = bundle.getString(MLAsrCaptureConstants.ASR_ERROR_MESSAGE)
Toast.makeText(this, "Error Code $errorMsg", Toast.LENGTH_LONG).show()
}
}
else -> {
Toast.makeText(this, "Failed to get data", Toast.LENGTH_LONG).show()
}
}
}
}
private fun performSearch(query: String) {
CoroutineScope(Dispatchers.IO).launch {
val searchKitInstance = SearchKitInstance.instance
val webSearchRequest = WebSearchRequest().apply {
setQ(query)
setLang(loadLang())
setSregion(loadRegion())
setPs(5)
setPn(1)
}
val response = searchKitInstance.webSearcher.search(webSearchRequest)
displayResults(response.data)
}
}
private fun displayResults(data: List<WebItem>) {
runOnUiThread {
adapter.items.apply {
clear()
addAll(data)
}
adapter.notifyDataSetChanged()
}
}
}
Output​
Conclusion​By using these 3 kits effortlessly, you can increase the quality of your application in a short time. I hope this article was useful to you. See you in other articles
References​Network Kit: https://developer.huawei.com/consum...s-V5/network-introduction-0000001050440045-V5
ML Kit: https://developer.huawei.com/consum...s-V5/service-introduction-0000001050040017-V5
Search Kit: https://developer.huawei.com/consum...re-Guides-V5/introduction-0000001055591730-V5

Expert: BestPal (Chatting) application using Huawei CloudDB, Auth service, Cloud Function and Push Kit

{
"lightbox_close": "Close",
"lightbox_next": "Next",
"lightbox_previous": "Previous",
"lightbox_error": "The requested content cannot be loaded. Please try again later.",
"lightbox_start_slideshow": "Start slideshow",
"lightbox_stop_slideshow": "Stop slideshow",
"lightbox_full_screen": "Full screen",
"lightbox_thumbnails": "Thumbnails",
"lightbox_download": "Download",
"lightbox_share": "Share",
"lightbox_zoom": "Zoom",
"lightbox_new_window": "New window",
"lightbox_toggle_sidebar": "Toggle sidebar"
}
Introduction
In this article, we can learn that chat option between two people, they can share text between each other. The application needs to have instant messaging so once a user sends the message to a friend over the application, the friend will receive the push notification at the given time. The quintessence of an app like instant application is available and react to ongoing actions. Also, push notifications can be an excellent promotional tool that can be used to inform users about updates and new functionalities.
Huawei Kits Used​
Huawei Cloud DB
Huawei Auth Service
Huawei Cloud function.
Huawei Push Kit
Huawei API Used​
Huawei CloudDB API - Cloud DB is used to store users data, users chat and also used to manage users chat history with other users.
a) Upsert
i) Insert data of the users from the profile.
ii) Create and insert room id, room id is consider as a reference between two users chat. Using room id will store all the respective chat data in the DB.
iii) Insert Chat data between two users based on the room id.
b) Query
i) Get list of Contacts for chat.
ii) Get list of users with whom logged in user chatted before.
ii) Get details of the chat screen with all the chat messages which includes images, text and location.
Huawei Auth Service – Using the Auth Service we are registering the user on the Ecosystem. We are using the Phone number auth service for the same to receive the OTP and verify the user here.
Huawei Cloud function – We are triggering the Huawei Push notification system using cloud function for the same.
Huawei Push kit - Push kit is used to push notification of message to other user. So when one user send message it will notify other user through push notification only.
Used the rest end point for the cloud function to send the push notification once the message is end, trigger from the device.
On HMSMessage Received This is once parsing the data as per our need on the implementation, so we need to parse image and location when shared by other success.
Database structure​
Now it's time to create project on Huawei console and development​Integration Preparations​You must complete the following preparations:
Register as a developer on Huawei console.
Create a project and an app in AppGallery Connect.
Generate and configure the signing certificate fingerprint.
Enable Auth service, Push and Cloud DB.
For details, refer to Configuring App Information in AppGallery Connect for HMS
First create cloud DB Zones
Create 3 object types
ChatRoomId: contain all chatting room id.
User: all register user details.
UserChat: all users chat details.
Let's start development with Login Page
We will login with Phone number using HMS Auth service.
Enable Phone number Authentication mode as shown in below image.
Add dependency
XML:
// HMS dependencies
implementation "com.huawei.agconnect:agconnect-database:$rootProject.ext.agdatabase"
implementation "com.huawei.agconnect:agconnect-auth:$rootProject.ext.agauth"
implementation "com.huawei.hms:push:$rootProject.ext.pushkit"
Enter the valid phone number, we will get OTP on same number using below method.
GET OTP
Java:
VerifyCodeSettings settings = new VerifyCodeSettings.Builder()
.action(VerifyCodeSettings.ACTION_REGISTER_LOGIN)
.sendInterval(30)
.locale(Locale.getDefault())
.build();
Task<VerifyCodeResult> task = AGConnectAuth.getInstance().requestVerifyCode(countryCodeStr, phoneNumberStr, settings);
task.addOnSuccessListener(TaskExecutors.immediate(), verifyCodeResult -> {
if (null != verifyCodeResult) {
verifyCodeResultMutableLiveData.postValue(verifyCodeResult);
}
});
task.addOnFailureListener(e ->
AppLog.logE(TAG, "onFailure: " + e.getCause()));
Verify Contact details
Java:
PhoneUser phoneUser = new PhoneUser.Builder()
.setCountryCode(countryCodeStr)
.setPhoneNumber(phoneNumberStr)
.setVerifyCode(code)
.build();
AGConnectAuth.getInstance().createUser(phoneUser)
.addOnSuccessListener(signInResult -> {
if (signInResult != null) {
User user = new User();
user.setUsername(signInResult.getUser().getDisplayName());
user.setPhoneNumber(phoneNumberStr);
userMutableLiveData.postValue(user);
}
})
.addOnFailureListener(e -> {
Log.e(TAG, "verifyContactDetails: " + e.getStackTrace());
User user = new User();
user.setPhoneNumber(phoneNumberStr);
userMutableLiveData.setValue(user);
});
After verify, user can authenticate successfully.
Now we have to complete the user profile, as in below picture you can see we have only phone number.
Create/ Update profile
Java:
public void saveUser(User user, Context context) {
CloudDBHelper.getInstance().openDb((isConnected, cloudDBZone) -> {
if (isConnected && cloudDBZone != null) {
if (cloudDBZone == null) {
return;
} else {
Task<Integer> insertTask = cloudDBZone.executeUpsert(user);
insertTask.addOnSuccessListener(integer -> {
userMutableLiveData.setValue(true);
CloudDBHelper.getInstance().closeDb(context);
}).addOnFailureListener(e -> {
userMutableLiveData.setValue(false);
CloudDBHelper.getInstance().closeDb(context);
});
}
}
});
}
Generate push token
Java:
GetToken getToken = new GetToken(app_id, UserProfileActivity.this);
getToken.setGetTokenListener(this);
getToken.execute();
GetToken class is a service class to generate push token
Java:
public class GetToken extends AsyncTask<Void, Void, String> {
private static final String TAG = GetToken.class.getSimpleName();
private Context context;
private String appId;
private GetTokenListener getTokenListener;
public GetToken(String appId, Context context) {
this.appId = appId;
this.context = context;
}
public void setGetTokenListener(GetTokenListener getTokenListener) {
this.getTokenListener = getTokenListener;
}
@Override
protected void onPreExecute() {
super.onPreExecute();
}
@Override
protected String doInBackground(Void... voids) {
try {
String pushToken = HmsInstanceId.getInstance(context).getToken(appId, HmsMessaging.DEFAULT_TOKEN_SCOPE);
AppLog.logD(TAG, pushToken);
getTokenListener.getToken(pushToken);
return pushToken;
} catch (ApiException e) {
e.printStackTrace();
}
return null;
}
@Override
protected void onPostExecute(String s) {
super.onPostExecute(s);
}
}
It will create the user profile and update data into Cloud DB.
Start chat for first time
We have to create room id for chatting between two people.
Java:
public void callCreateRoomId(final String userMobileTo, final String userMobileFrom) {
CloudDBHelper.getInstance().openDb(new OnDBZoneOpen() {
@Override
public void isDBZoneOpen(boolean isConnected, CloudDBZone cloudDBZone) {
if (cloudDBZone != null) {
ChatRoomId roomId = new ChatRoomId();
mRoomDataIndex = mRoomDataIndex + 1;
AppLog.logE(TAG, "New ROOM IS WILL BE ===> " + mRoomDataIndex);
roomId.setRoom_id(String.valueOf(mRoomDataIndex));
roomId.setUser_mobile_to(userMobileTo);
roomId.setUser_mobile_from(userMobileFrom);
roomId.setUpdate_shadow_flag(true);
Task<Integer> insertTask = cloudDBZone.executeUpsert(roomId);
insertTask.addOnSuccessListener(insertSuccessListener(roomId))
.addOnFailureListener(new OnFailureListener() {
@Override
public void onFailure(Exception e) {
AppLog.logE(TAG, "Exception in creating room id " + e.getLocalizedMessage());
}
}).addOnCanceledListener(new OnCanceledListener() {
@Override
public void onCanceled() {
AppLog.logE(TAG, "Inside on cancel listener");
}
});
} else {
if (mOnApiError != null) {
mOnApiError.onError("Cloud database zone is null", new Throwable("CloudDBZone is null"));
}
}
}
});
}
Get previous chats from cloudDB
Java:
public void getUserChatByRoomID(String roomId, Context context) {
CloudDBZoneQuery<UserChat> query = CloudDBZoneQuery.where(UserChat.class).equalTo(DBConstants.roomId, roomId).orderByAsc(DBConstants.MESSAGE_TIMESTAMP);
getUserChat(query, context);
}
private void getUserChat(CloudDBZoneQuery<UserChat> userQuery, Context context) {
CloudDBHelper.getInstance().openDb((isConnected, cloudDBZone) -> {
Task<CloudDBZoneSnapshot<UserChat>> queryTask = cloudDBZone.executeQuery(userQuery,
CloudDBZoneQuery.CloudDBZoneQueryPolicy.POLICY_QUERY_FROM_CLOUD_ONLY);
queryTask.addOnSuccessListener(userChatCloudDBZoneSnapshot -> {
processSnapShot(userChatCloudDBZoneSnapshot.getSnapshotObjects(), context);
});
});
}
private void processSnapShot(CloudDBZoneObjectList<UserChat> userCloudDBZoneSnapshot, Context context) {
if (userCloudDBZoneSnapshot != null) {
ArrayList<UserChat> users = new ArrayList<>();
while (userCloudDBZoneSnapshot.hasNext()) {
UserChat user = null;
try {
user = userCloudDBZoneSnapshot.next();
users.add(user);
} catch (AGConnectCloudDBException e) {
e.printStackTrace();
CloudDBHelper.getInstance().closeDb(context);
}
}
userChatMutableLiveData.setValue(users);
CloudDBHelper.getInstance().closeDb(context);
}
}
Start Sending chat messages
messageType: user can send message in text, image, location or in video Types.
Java:
private void setMessage(String messageType) {
Util.showProgressBar(MessageActivity.this);
UserChat userChat = new UserChat();
userChat.setRoom_id(roomId);
userChat.setMessage_timestamp(Long.parseLong(Util.getTimeStamp()));
userChat.setChat_id(Util.getRandomNumber());
userChat.setReceiver_name(receiverText);
userChat.setReceiver_phone(receiverPhoneNumber);
userChat.setSender_name(ChitChatSharedPref.getInstance().getString(Constants.USER_NAME, ""));
userChat.setSender_phone(ChitChatSharedPref.getInstance().getString(Constants.PHONE_NUMBER, ""));
userChat.setMessage_type(messageType);
switch (messageType) {
case Constants.MESSAGE_TYPE_TEXT:
userChat.setMessage_data(textSend.getText().toString());
messageViewModel.saveUserChat(userChat);
messageViewModel.userUpdatedSuccessfully.observe(MessageActivity.this, aBoolean -> {
if (aBoolean) {
Util.stopProgressBar();
getChatList();
} else {
Util.stopProgressBar();
}
});
break;
}
messageViewModel.queryForToken(receiverPhoneNumber, MessageActivity.this);
}
It will save user data into cloud dB
Java:
public void saveUserChat(UserChat userChat) {
CloudDBHelper.getInstance().openDb((isConnected, cloudDBZone) -> {
if (cloudDBZone != null) {
Task<Integer> insertTask = cloudDBZone.executeUpsert(userChat);
insertTask
.addOnSuccessListener(integer ->
userUpdatedSuccessfully.setValue(true))
.addOnFailureListener(e -> {
userUpdatedSuccessfully.setValue(false);
AppLog.logE(TAG, e.getMessage());
});
} else {
userUpdatedSuccessfully.setValue(false);
}
});
}
It's time to send push notification
Java:
public void queryForToken(String phoneNumber, Context context) {
CloudDBZoneQuery<User> query = CloudDBZoneQuery.where(User.class).equalTo(DBConstants.userNumber, phoneNumber);
processNumberCheck(query, context);
}
messageViewModel.tokenMutableLiveData.observe(MessageActivity.this, s -> {
PushApis pushApis = new PushApis(MessageActivity.this);
if (messageType.equalsIgnoreCase(Constants.MESSAGE_TYPE_TEXT)) {
pushApis.sendPushNotification(roomId, messageType, "104739093", MessageActivity.this.textSend.getText().toString(), s);
textSend.setText("");
}
});
Setting up push messaging API's
Java:
public class PushApis {
private Context context;
public PushApis(Context context) {
this.context = context;
}
public void sendPushNotification(String chatId, String message, String appId, String messageData, String userPushTokens) {
try {
StrictMode.ThreadPolicy policy = new StrictMode.ThreadPolicy.Builder().permitAll().build();
StrictMode.setThreadPolicy(policy);
String response = "";
URL url = new URL(Constants.TOKEN_URL);
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
connection.setDoOutput(true);
connection.setInstanceFollowRedirects(false);
connection.setRequestMethod("POST");
connection.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
connection.setRequestProperty("POST", "/oauth2/v3/token HTTP/1.1");
connection.setRequestProperty("Host", "oauth-login.cloud.huawei.com");
HashMap<String, String> params = new HashMap<>();
params.put("grant_type", "client_credentials");
params.put("client_secret", Constants.CLIENT_SECRET);
params.put("client_id", Constants.CLIENT_ID);
String postDataLength = getDataString(params);
OutputStream os = connection.getOutputStream();
BufferedWriter writer = new BufferedWriter(
new OutputStreamWriter(os, "UTF-8"));
writer.write(postDataLength);
writer.flush();
writer.close();
os.close();
int responseCode = connection.getResponseCode();
if (responseCode == HttpsURLConnection.HTTP_OK) {
String line;
BufferedReader br = new BufferedReader(new InputStreamReader(connection.getInputStream()));
while ((line = br.readLine()) != null) {
response += line;
}
} else {
response = "";
}
AppLog.logE("Response", response);
Gson gson = new Gson();
BearerRequest bearerRequest = gson.fromJson(response, BearerRequest.class);
triggerPush(bearerRequest.getAccess_token(), appId, chatId, message, messageData, userPushTokens);
} catch (Exception e) {
e.printStackTrace();
}
}
private String getDataString(HashMap<String, String> params) throws UnsupportedEncodingException {
StringBuilder result = new StringBuilder();
boolean first = true;
for (Map.Entry<String, String> entry : params.entrySet()) {
if (first)
first = false;
else
result.append("&");
result.append(URLEncoder.encode(entry.getKey(), "UTF-8"));
result.append("=");
result.append(URLEncoder.encode(entry.getValue(), "UTF-8"));
}
return result.toString();
}
private void triggerPush(String bearer, String appId, String chatId, String messageType, String messageData, String userPushTokens) {
try {
StrictMode.ThreadPolicy policy = new StrictMode.ThreadPolicy.Builder().permitAll().build();
StrictMode.setThreadPolicy(policy);
String response = null;
URL url = new URL("https://push-api.cloud.huawei.com/v1/" + appId + "/messages:send");
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
connection.setDoOutput(true);
connection.setInstanceFollowRedirects(false);
connection.setRequestMethod("POST");
connection.setDoOutput(true);
connection.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
connection.setRequestProperty("Authorization", "Bearer " + bearer);
connection.setRequestProperty("Host", "oauth-login.cloud.huawei.com");
connection.setRequestProperty("POST", "/oauth2/v2/token HTTP/1.1");
OutputStream os = connection.getOutputStream();
Data data = new Data();
data.message = messageType;
data.roomId = chatId;
data.messageData = messageData;
data.sender_name = senderName;
data.sender_phone = senderPhone;
data.title = context.getResources().getString(R.string.app_name);
ArrayList<String> token = new ArrayList<>();
token.add(userPushTokens);
Message message = new Message();
message.tokens = token;
message.data = data.toString();
PushMessageRequest pushMessageRequest = new PushMessageRequest();
pushMessageRequest.message = message;
pushMessageRequest.validate_only = false;
BufferedWriter writer = new BufferedWriter(
new OutputStreamWriter(os, "UTF-8"));
Gson gson = new Gson();
JSONObject jsonObject = new JSONObject(gson.toJson(pushMessageRequest, PushMessageRequest.class));
writer.write(jsonObject.toString());
writer.flush();
writer.close();
os.close();
int responseCode = connection.getResponseCode();
String line = null;
BufferedReader br = new BufferedReader(new InputStreamReader(connection.getInputStream()));
while ((line = br.readLine()) != null) {
response += line;
}
AppLog.logE("Response", response);
} catch (Exception e) {
e.getStackTrace();
}
}
}
Conclusion
In this article, we have learned how we can create a simple messaging application with cloud dB, auth service and push kit. We can also use cloud storage for store profile picture, location, documents or audio and video files.
Thanks for reading this article. Be sure to like and comment to this article, if you found it helpful. It means a lot to me.
Reference
https://developer.huawei.com/consumer/en/agconnect/cloud-base/
https://developer.huawei.com/consum...-Guides/service-introduction-0000001050040060
https://developer.huawei.com/consumer/en/agconnect/auth-service/

How to Automatically Fill Addresses in Lifestyle Apps

Filling in addresses is a task that users of lifestyle apps and mini programs that provide services such as group buying, takeout, package delivery, housekeeping, logistics, and moving services often have to perform. Generally, this requires users to manually fill in their address information, for example, selecting California, Los Angeles, and Hollywood Blvd in sequence using several drop-down list boxes and then manually entering their names and phone numbers. This process usually takes some time and is prone to input error.
Wouldn't it be handy if there was an automatic way for users to fill in addresses quickly and accurately? With HMS Core Location Kit's fused location and geocoding capabilities, a lifestyle app can automatically pinpoint the current location of a user or obtain the street address of a map location, and fill that information in the address box. Thanks to this, users are freed from the hassle of having to manually enter addresses, as well preventing human error. In this article, I will explain how you can easily integrate this feature into your app and provide you with sample code.
Demo​
{
"lightbox_close": "Close",
"lightbox_next": "Next",
"lightbox_previous": "Previous",
"lightbox_error": "The requested content cannot be loaded. Please try again later.",
"lightbox_start_slideshow": "Start slideshow",
"lightbox_stop_slideshow": "Stop slideshow",
"lightbox_full_screen": "Full screen",
"lightbox_thumbnails": "Thumbnails",
"lightbox_download": "Download",
"lightbox_share": "Share",
"lightbox_zoom": "Zoom",
"lightbox_new_window": "New window",
"lightbox_toggle_sidebar": "Toggle sidebar"
}
Development Procedure​Prepare for the development​1. Sign in to AppGallery Connect and click My projects. Find your project, go to Project settings > Manage APIs, and toggle on the Location Kit switch. Then, click the app for which you need to configure the signing certificate fingerprint, and go to Project settings > General information. In the App information area, click Add next to SHA-256 certificate fingerprint, and enter the SHA-256 certificate fingerprint.
2. Go to Project settings > General information. In the App information area, click agconnect-services.json to download the configuration file. Then, copy the configuration file to the app's root directory.
3. Configure the project-level build.gradle file.
Java:
buildscript {
repositories {
google()
jcenter()
maven { url 'https://developer.huawei.com/repo/' }
mavenCentral()
}
dependencies {
classpath 'com.android.tools.build:gradle:4.1.2'
classpath 'com.huawei.agconnect:agcp:1.6.0.300'
}
}
allprojects {
repositories {
maven { url 'https://developer.huawei.com/repo/' }
google()
jcenter()
mavenCentral()
}
}
Configure the app-level build.gradle file.
Java:
plugins {
id 'com.android.application'
id 'com.huawei.agconnect'
}
Add the following build dependency in the dependencies block in the app-level build.gradle file:
Java:
implementation 'com.huawei.hms:location:6.3.0.300'
Check permissions​1. Declare the ACCESS_COARSE_LOCATION (approximate location permission), ACCESS_FINE_LOCATION (precise location permission), and ACCESS_BACKGROUND_LOCATION permissions in the AndroidManifest.xml file.
Java:
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_BACKGROUND_LOCATION" />
2. Dynamically apply for related location permissions (according to requirements for dangerous permissions in Android 6.0 or later).
Java:
if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.P) {
Log.i(TAG, "android sdk < 28 Q");
if (ActivityCompat.checkSelfPermission(this,
Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED
&& ActivityCompat.checkSelfPermission(this,
Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
String[] strings =
{Manifest.permission.ACCESS_FINE_LOCATION, Manifest.permission.ACCESS_COARSE_LOCATION};
ActivityCompat.requestPermissions(this, strings, 1);
}
} else {
if (ActivityCompat.checkSelfPermission(this,
Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED
&& ActivityCompat.checkSelfPermission(this,
Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED
&& ActivityCompat.checkSelfPermission(this,
"android.permission.ACCESS_BACKGROUND_LOCATION") != PackageManager.PERMISSION_GRANTED) {
String[] strings = {Manifest.permission.ACCESS_FINE_LOCATION,
Manifest.permission.ACCESS_COARSE_LOCATION,
"android.permission.ACCESS_BACKGROUND_LOCATION"};
ActivityCompat.requestPermissions(this, strings, 2);
}
}
Obtain the location result​1. Set location parameters, including the location update interval and location type
Java:
mFusedLocationProviderClient = LocationServices.getFusedLocationProviderClient(this);
mSettingsClient = LocationServices.getSettingsClient(this);
mLocationRequest = new LocationRequest();
// Set the location update interval, in milliseconds.
mLocationRequest.setInterval(5000);
// Set the priority.
mLocationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
2. Call the getSettingsClient() method to obtain a SettingsClient instance, and call checkLocationSettings() to check the device location settings.
Java:
LocationSettingsRequest locationSettingsRequest = builder.build();
// Before requesting location updates, call checkLocationSettings to check the device location settings.
Task<LocationSettingsResponse> locationSettingsResponseTask =
mSettingsClient.checkLocationSettings(locationSettingsRequest);
After checking that the device location function is enabled, call requestLocationUpdates() to request location updates.
Java:
locationSettingsResponseTask.addOnSuccessListener(new OnSuccessListener<LocationSettingsResponse>() {
@Override
public void onSuccess(LocationSettingsResponse locationSettingsResponse) {
Log.i(TAG, "check location settings success");
mFusedLocationProviderClient
.requestLocationUpdates(mLocationRequest, mLocationCallback, Looper.getMainLooper())
.addOnSuccessListener(new OnSuccessListener<Void>() {
@Override
public void onSuccess(Void aVoid) {
Log.i(TAG, "requestLocationUpdatesWithCallback onSuccess");
}
})
.addOnFailureListener(new OnFailureListener() {
@Override
public void onFailure(Exception e) {
Log.e(TAG, "requestLocationUpdatesWithCallback onFailure:" + e.getMessage());
}
});
}
}).addOnFailureListener(new OnFailureListener() {
@Override
public void onFailure(Exception e) {
Log.e(TAG, "checkLocationSetting onFailure:" + e.getMessage());
int statusCode = 0;
if (e instanceof ApiException) {
statusCode = ((ApiException) e).getStatusCode();
}
switch (statusCode) {
case LocationSettingsStatusCodes.RESOLUTION_REQUIRED:
try {
// When startResolutionForResult is called, a popup will
// appear, asking the user to grant relevant permissions.
if (e instanceof ResolvableApiException) {
ResolvableApiException rae = (ResolvableApiException) e;
rae.startResolutionForResult(MainActivity.this, 0);
}
} catch (IntentSender.SendIntentException sie) {
Log.e(TAG, "PendingIntent unable to execute request.");
}
break;
default:
break;
}
}
});
Obtain the address of the current location through reverse geocoding​After obtaining the longitude and latitude of a location, pass them to the geocoding service (GeocoderService) to obtain a geocoding request object. Then, call the getFromLocation method and set request (GetFromLocationRequest) parameters to obtain the address of the location.
Java:
if (null == mLocationCallback) {
mLocationCallback = new LocationCallback() {
@Override
public void onLocationResult(LocationResult locationResult) {
if (locationResult != null) {
List<Location> locations = locationResult.getLocations();
if (!locations.isEmpty()) {
ExecutorUtil.getInstance().execute(new Runnable() {
@Override
public void run() {
Locale locale = new Locale("zh", "CN");
GeocoderService geocoderService = LocationServices.getGeocoderService(MainActivity.this, locale);
GetFromLocationRequest getFromLocationRequest = new GetFromLocationRequest(locations.get(0).getLatitude(), locations.get(0).getLongitude(), 1);
geocoderService.getFromLocation(getFromLocationRequest)
.addOnSuccessListener(new OnSuccessListener<List<HWLocation>>() {
@Override
public void onSuccess(List<HWLocation> hwLocation) {
printGeocoderResult(hwLocation);
}
})
.addOnFailureListener(new OnFailureListener() {
@Override
public void onFailure(Exception e) {
Log.i(TAG, e.getMessage());
}
});
}
});
}
}
}
@Override
public void onLocationAvailability(LocationAvailability locationAvailability) {
if (locationAvailability != null) {
boolean flag = locationAvailability.isLocationAvailable();
Log.i(TAG, "onLocationAvailability isLocationAvailable:" + flag);
}
}
};
}
Finally, display the obtained address on the screen to complete the implementation.
References​>> Location Kit official website
>> Location Kit Development Guide
>> Reddit to join developer discussions
>> GitHub to download the sample code
>> Stack Overflow to solve integration problems

Categories

Resources