Introduction
Site Kit is basically used for apps to provide the place related services. This kit provide to search the places with keyword, Find nearby place, place suggestion for user input, Get place details using the unique id.
Features of Huawei Site Kit
Keyword search: Returns a place list based on keywords entered by the user.
Nearby place search: Searches for nearby places based on the current location of the user's device.
Place details: Searches for details about a place.
Search suggestion: Returns a list of place suggestions.
Site Search: Returns a site object.
Development Overview
You need to install Android Studio IDE and I assume that you have prior knowledge of Android application development.
Hardware Requirements
A computer (desktop or laptop) running Windows 10.
Android phone (with the USB cable), which is used for debugging.
Software Requirements
Java JDK 1.8 or later.
Android Studio software or Visual Studio or Code installed.
HMS Core (APK) 4.X or later
Integration steps
Step 1. Huawei developer account and complete identity verification in Huawei developer website, refer to register Huawei ID.
Step 2. Create project in AppGallery Connect
Step 3. Adding HMS Core SDK
Let's start coding
MainActivity.kt
Java:
package com.huawei.hms.knowmyboard.dtse.activity.view
import androidx.navigation.Navigation.findNavController
import androidx.navigation.ui.NavigationUI.setupWithNavController
import com.huawei.hms.knowmyboard.dtse.activity.viewmodel.LoginViewModel
import android.graphics.Bitmap
import com.huawei.hms.mlsdk.langdetect.local.MLLocalLangDetector
import com.huawei.hms.mlsdk.translate.local.MLLocalTranslator
import android.app.ProgressDialog
import androidx.navigation.NavController
import android.os.Bundle
import androidx.databinding.DataBindingUtil
import com.huawei.hms.knowmyboard.dtse.activity.app.MyApplication
import android.content.Intent
import com.huawei.hms.support.account.AccountAuthManager
import android.provider.MediaStore
import com.huawei.hmf.tasks.OnSuccessListener
import com.huawei.hms.mlsdk.langdetect.MLLangDetectorFactory
import com.huawei.hms.mlsdk.langdetect.local.MLLocalLangDetectorSetting
import com.huawei.hmf.tasks.OnFailureListener
import android.content.DialogInterface
import android.net.Uri
import android.util.Log
import androidx.appcompat.app.AlertDialog
import androidx.appcompat.app.AppCompatActivity
import androidx.lifecycle.ViewModelProvider
import com.google.android.material.bottomnavigation.BottomNavigationView
import com.huawei.hms.common.ApiException
import com.huawei.hms.knowmyboard.dtse.R
import com.huawei.hms.knowmyboard.dtse.activity.model.UserData
import com.huawei.hms.knowmyboard.dtse.activity.util.Constants
import com.huawei.hms.knowmyboard.dtse.databinding.ActivityMainBinding
import com.huawei.hms.mlsdk.MLAnalyzerFactory
import com.huawei.hms.mlsdk.common.MLApplication
import com.huawei.hms.mlsdk.common.MLFrame
import com.huawei.hms.mlsdk.translate.local.MLLocalTranslateSetting
import com.huawei.hms.mlsdk.translate.MLTranslatorFactory
import com.huawei.hms.mlsdk.model.download.MLModelDownloadStrategy
import com.huawei.hms.mlsdk.model.download.MLModelDownloadListener
import com.huawei.hms.mlsdk.text.MLLocalTextSetting
import com.huawei.hms.mlsdk.text.MLText
import com.huawei.hms.mlsdk.text.MLTextAnalyzer
import java.io.IOException
import java.lang.Exception
import java.util.ArrayList
class MainActivity() : AppCompatActivity() {
var loginViewModel: LoginViewModel? = null
private var mTextAnalyzer: MLTextAnalyzer? = null
var imagePath: Uri? = null
var bitmap: Bitmap? = null
var result = ArrayList<String>()
var myLocalLangDetector: MLLocalLangDetector? = null
var myLocalTranslator: MLLocalTranslator? = null
var textRecognized: String? = null
var progressDialog: ProgressDialog? = null
var navController: NavController? = null
var activityMainBinding: ActivityMainBinding? = null
var bottomNavigationView: BottomNavigationView? = null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
activityMainBinding =
DataBindingUtil.setContentView([email protected], R.layout.activity_main)
loginViewModel = ViewModelProvider([email protected]).get(
LoginViewModel::class.java
)
navController = findNavController([email protected], R.id.nav_host_fragment)
MyApplication.activity = this
progressDialog = ProgressDialog(this)
progressDialog!!.setCancelable(false)
bottomNavigationView = activityMainBinding!!.bottomNavigation
setupWithNavController(bottomNavigationView!!, navController!!)
}
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
// Process the authorization result to obtain the authorization code from AuthAccount.
super.onActivityResult(requestCode, resultCode, data)
if (requestCode == 1234) {
Log.e("TAG", " Result can be pulled")
}
if (requestCode == 8888) {
val authAccountTask = AccountAuthManager.parseAuthResultFromIntent(data)
if (authAccountTask.isSuccessful) {
// The sign-in is successful, and the user's ID information and authorization code are obtained.
val authAccount = authAccountTask.result
val userData = UserData()
userData.accessToken = authAccount.accessToken
userData.countryCode = authAccount.countryCode
userData.displayName = authAccount.displayName
userData.email = authAccount.email
userData.familyName = authAccount.familyName
userData.givenName = authAccount.givenName
userData.idToken = authAccount.idToken
userData.openId = authAccount.openId
userData.uid = authAccount.uid
userData.photoUriString = authAccount.avatarUri.toString()
userData.unionId = authAccount.unionId
loginViewModel = ViewModelProvider([email protected]).get(
LoginViewModel::class.java
)
loginViewModel!!.sendData(authAccount.displayName)
} else {
// The sign-in failed.
Log.e(
"TAG",
"sign in failed:" + (authAccountTask.exception as ApiException).statusCode
)
}
}
if ((requestCode == 2323) && (resultCode == RESULT_OK) && (data != null)) {
progressDialog!!.setMessage("Initializing text detection..")
progressDialog!!.show()
imagePath = data.data
try {
bitmap = MediaStore.Images.Media.getBitmap(this.contentResolver, imagePath)
asyncAnalyzeText(bitmap)
} catch (e: IOException) {
e.printStackTrace()
Log.e("TAG", " BITMAP ERROR")
}
}
if ((requestCode == 2424) && (resultCode == RESULT_OK) && (data != null)) {
progressDialog!!.setMessage("Initializing text detection..")
progressDialog!!.show()
try {
bitmap = data.extras!!["data"] as Bitmap?
asyncAnalyzeText(bitmap)
} catch (e: Exception) {
e.printStackTrace()
Log.e("TAG", " BITMAP ERROR")
}
}
}
private fun asyncAnalyzeText(bitmap: Bitmap?) {
if (mTextAnalyzer == null) {
createMLTextAnalyzer()
}
val frame = MLFrame.fromBitmap(bitmap)
val task = mTextAnalyzer!!.asyncAnalyseFrame(frame)
task.addOnSuccessListener(object : OnSuccessListener<MLText> {
override fun onSuccess(text: MLText) {
progressDialog!!.setMessage("Initializing language detection..")
textRecognized = text.stringValue.trim { it <= ' ' }
if (!textRecognized!!.isEmpty()) {
// Create a local language detector.
val factory = MLLangDetectorFactory.getInstance()
val setting =
MLLocalLangDetectorSetting.Factory() // Set the minimum confidence threshold for language detection.
.setTrustedThreshold(0.01f)
.create()
myLocalLangDetector = factory.getLocalLangDetector(setting)
val firstBestDetectTask = myLocalLangDetector!!.firstBestDetect(textRecognized)
firstBestDetectTask.addOnSuccessListener(OnSuccessListener { languageDetected ->
progressDialog!!.setMessage("Initializing text translation..")
// Processing logic for detection success.
textTranslate(languageDetected, textRecognized!!, bitmap)
}).addOnFailureListener(object : OnFailureListener {
override fun onFailure(e: Exception) {
// Processing logic for detection failure.
Log.e("TAG", "Lang detect error:" + e.message)
}
})
} else {
progressDialog!!.dismiss()
showErrorDialog("Failed to recognize text.")
}
}
}).addOnFailureListener(object : OnFailureListener {
override fun onFailure(e: Exception) {
Log.e("TAG", "#==>" + e.message)
}
})
}
private fun showErrorDialog(msg: String) {
val alertDialog = AlertDialog.Builder(this).create()
alertDialog.setTitle("Error")
alertDialog.setMessage(msg)
alertDialog.setButton(
AlertDialog.BUTTON_POSITIVE,
"OK",
object : DialogInterface.OnClickListener {
override fun onClick(dialog: DialogInterface, which: Int) {
dialog.dismiss()
}
})
alertDialog.show()
}
private fun textTranslate(languageDetected: String, textRecognized: String, uri: Bitmap?) {
MLApplication.initialize(application)
MLApplication.getInstance().apiKey = Constants.API_KEY
// Create an offline translator.
val setting =
MLLocalTranslateSetting.Factory() // Set the source language code. The ISO 639-1 standard is used. This parameter is mandatory. If this parameter is not set, an error may occur.
.setSourceLangCode(languageDetected) // Set the target language code. The ISO 639-1 standard is used. This parameter is mandatory. If this parameter is not set, an error may occur.
.setTargetLangCode("en")
.create()
myLocalTranslator = MLTranslatorFactory.getInstance().getLocalTranslator(setting)
// Set the model download policy.
val downloadStrategy = MLModelDownloadStrategy.Factory()
.needWifi() // It is recommended that you download the package in a Wi-Fi environment.
.create()
// Create a download progress listener.
val modelDownloadListener: MLModelDownloadListener = object : MLModelDownloadListener {
override fun onProcess(alreadyDownLength: Long, totalLength: Long) {
runOnUiThread(object : Runnable {
override fun run() {
// Display the download progress or perform other operations.
}
})
}
}
myLocalTranslator!!.preparedModel(downloadStrategy, modelDownloadListener)
.addOnSuccessListener(object : OnSuccessListener<Void?> {
override fun onSuccess(aVoid: Void?) {
// Called when the model package is successfully downloaded.
// input is a string of less than 5000 characters.
val task = myLocalTranslator!!.asyncTranslate(textRecognized)
// Before translation, ensure that the models have been successfully downloaded.
task.addOnSuccessListener(object : OnSuccessListener<String> {
override fun onSuccess(translated: String) {
// Processing logic for detection success.
result.clear()
result.add(languageDetected.trim { it <= ' ' })
result.add(textRecognized.trim { it <= ' ' })
result.add(translated.trim { it <= ' ' })
loginViewModel!!.setImage(uri!!)
loginViewModel!!.setTextRecongnized(result)
progressDialog!!.dismiss()
}
}).addOnFailureListener(object : OnFailureListener {
override fun onFailure(e: Exception) {
// Processing logic for detection failure.
progressDialog!!.dismiss()
}
})
}
}).addOnFailureListener(object : OnFailureListener {
override fun onFailure(e: Exception) {
// Called when the model package fails to be downloaded.
progressDialog!!.dismiss()
}
})
}
private fun createMLTextAnalyzer() {
val setting = MLLocalTextSetting.Factory()
.setOCRMode(MLLocalTextSetting.OCR_DETECT_MODE)
.create()
mTextAnalyzer = MLAnalyzerFactory.getInstance().getLocalTextAnalyzer(setting)
}
override fun onStop() {
if (myLocalLangDetector != null) {
myLocalLangDetector!!.stop()
}
if (myLocalTranslator != null) {
myLocalTranslator!!.stop()
}
if (progressDialog != null) {
progressDialog!!.dismiss()
}
super.onStop()
}
companion object {
var TAG = "TAG"
}
}
LoginViewModel.kt
Java:
package com.huawei.hms.knowmyboard.dtse.activity.viewmodel
import android.app.Application
import com.huawei.hms.support.account.service.AccountAuthService
import android.graphics.Bitmap
import com.huawei.hms.location.LocationResult
import com.huawei.hms.site.api.model.Site
import android.widget.Toast
import androidx.lifecycle.AndroidViewModel
import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
import com.huawei.hms.common.ApiException
import com.huawei.hms.knowmyboard.dtse.R
import com.huawei.hms.support.account.request.AccountAuthParams
import com.huawei.hms.support.account.request.AccountAuthParamsHelper
import com.huawei.hms.support.account.AccountAuthManager
import com.huawei.hms.knowmyboard.dtse.activity.app.MyApplication
import java.util.ArrayList
class LoginViewModel(application: Application) : AndroidViewModel(application) {
var service: AccountAuthService? = null
val message = MutableLiveData<String>()
val textRecongnized = MutableLiveData<ArrayList<String>>()
val imagePath = MutableLiveData<Bitmap>()
val locationResult = MutableLiveData<LocationResult>()
val siteSelected = MutableLiveData<Site>()
fun getSiteSelected(): LiveData<Site> {
return siteSelected
}
fun setSiteSelected(siteSelected: Site) {
this.siteSelected.value = siteSelected
}
fun sendData(msg: String) {
message.value = msg
}
fun getMessage(): LiveData<String> {
return message
}
fun setImage(imagePath: Bitmap) {
this.imagePath.value = imagePath
}
fun setLocationResult(locationResult: LocationResult) {
this.locationResult.value = locationResult
}
fun setTextRecongnized(textRecongnized: ArrayList<String>) {
this.textRecongnized.value = textRecongnized
}
fun logoutHuaweiID() {
if (service != null) {
service!!.signOut()
sendData("KnowMyBoard")
Toast.makeText(getApplication(), "You are logged out from Huawei ID", Toast.LENGTH_LONG)
.show()
}
}
fun loginClicked() {
val authParams =
AccountAuthParamsHelper(AccountAuthParams.DEFAULT_AUTH_REQUEST_PARAM).setAuthorizationCode()
.createParams()
service = AccountAuthManager.getService(MyApplication.activity, authParams)
MyApplication.activity!!.startActivityForResult(service!!.signInIntent, 8888)
}
fun cancelAuthorization() {
if (service != null) {
// service indicates the AccountAuthService instance generated using the getService method during the sign-in authorization.
service!!.cancelAuthorization().addOnCompleteListener { task ->
if (task.isSuccessful) {
// Processing after a successful authorization cancellation.
sendData(getApplication<Application>().resources.getResourceName(R.string.app_name))
Toast.makeText(getApplication(), "Cancelled authorization", Toast.LENGTH_LONG)
.show()
} else {
// Handle the exception.
val exception = task.exception
if (exception is ApiException) {
val statusCode = exception.statusCode
Toast.makeText(
getApplication(),
"Failed to cancel authorization. status code $statusCode",
Toast.LENGTH_LONG
).show()
}
}
}
} else {
Toast.makeText(getApplication(), "Login required", Toast.LENGTH_LONG).show()
}
}
}
SearchFragment.kt
Java:
package com.huawei.hms.knowmyboard.dtse.activity.fragments
import androidx.navigation.Navigation.findNavController
import com.huawei.hms.knowmyboard.dtse.activity.viewmodel.LoginViewModel
import androidx.navigation.NavController
import com.huawei.hms.site.api.SearchService
import com.huawei.hms.knowmyboard.dtse.activity.adapter.SitesAdapter
import com.huawei.hms.site.api.model.Site
import com.huawei.hms.location.LocationResult
import com.huawei.hms.knowmyboard.dtse.activity.intefaces.ItemClickListener
import android.view.WindowManager
import android.view.LayoutInflater
import android.view.ViewGroup
import android.os.Bundle
import android.util.Log
import android.view.View
import androidx.appcompat.widget.SearchView
import androidx.databinding.DataBindingUtil
import androidx.fragment.app.Fragment
import androidx.lifecycle.ViewModelProvider
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import com.huawei.hms.knowmyboard.dtse.R
import com.huawei.hms.knowmyboard.dtse.activity.util.Constants
import com.huawei.hms.knowmyboard.dtse.databinding.FragmentSearchBinding
import com.huawei.hms.site.api.SearchServiceFactory
import com.huawei.hms.site.api.model.TextSearchRequest
import com.huawei.hms.site.api.model.Coordinate
import com.huawei.hms.site.api.SearchResultListener
import com.huawei.hms.site.api.model.TextSearchResponse
import com.huawei.hms.site.api.model.SearchStatus
import com.huawei.hms.site.api.model.NearbySearchRequest
import com.huawei.hms.site.api.model.HwLocationType
import com.huawei.hms.site.api.model.NearbySearchResponse
import java.io.UnsupportedEncodingException
import java.lang.Exception
import java.net.URLEncoder
import java.util.ArrayList
class SearchFragment : Fragment() {
var binding: FragmentSearchBinding? = null
var loginViewModel: LoginViewModel? = null
//View view;
var navController: NavController? = null
private var searchService: SearchService? = null
var adapter: SitesAdapter? = null
var siteArrayList = ArrayList<Site>()
var locationResult: LocationResult? = null
/* var siteClicklistener = ItemClickListener { vh, site, pos ->
requireActivity().window.setSoftInputMode(
WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_HIDDEN
)
loginViewModel!!.setSiteSelected(site)
navController!!.navigate(R.id.loginFragment)
}*/
var siteClicklistener = object : ItemClickListener{
override fun onItemClicked(vh: RecyclerView.ViewHolder?, item: Site?, pos: Int) {
requireActivity().window.setSoftInputMode(
WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_HIDDEN
)
loginViewModel!!.setSiteSelected(item!!)
navController!!.navigate(R.id.loginFragment)
}
}
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
requireActivity().window.setSoftInputMode(
WindowManager.LayoutParams.SOFT_INPUT_STATE_VISIBLE
)
binding = DataBindingUtil.inflate(inflater, R.layout.fragment_search, container, false)
loginViewModel = ViewModelProvider(requireActivity()).get(
LoginViewModel::class.java
)
val searchView = binding!!.edSearch
val recyclerView = binding!!.suggestionRv
navController = findNavController(requireActivity(), R.id.nav_host_fragment)
searchView.isFocusable = true
searchView.onActionViewExpanded()
adapter = SitesAdapter(siteArrayList, context, siteClicklistener)
recyclerView.adapter = adapter
recyclerView.layoutManager = LinearLayoutManager(context)
recyclerView.setHasFixedSize(true)
loginViewModel!!.locationResult.observeForever { locationResult1 ->
locationResult = locationResult1
}
searchView.setOnQueryTextListener(object : SearchView.OnQueryTextListener {
override fun onQueryTextSubmit(query: String): Boolean {
return false
}
override fun onQueryTextChange(newText: String): Boolean {
if (newText.length > 4) {
nearByPlacesSearch(newText)
}
return false
}
})
return binding!!.root
}
fun keywordSearch(search: String?) {
try {
val key = URLEncoder.encode(Constants.API_KEY, "UTF-8")
// Instantiate the SearchService object.
searchService = SearchServiceFactory.create(context, key)
// Create a request body.
val request = TextSearchRequest()
request.query = search
if (locationResult != null) {
val location = Coordinate(
locationResult!!.lastHWLocation.latitude,
locationResult!!.lastHWLocation.longitude
)
request.location = location
}
request.radius = 1000
//request.setHwPoiType(HwLocationType.HOTEL_MOTEL);
request.countryCode = "IN"
request.language = "en"
request.pageIndex = 1
request.pageSize = 5
request.isChildren = false
// request.setCountries(Arrays.asList("en", "fr", "cn", "de", "ko","in"));
// Create a search result listener.
val resultListener: SearchResultListener<TextSearchResponse?> =
object : SearchResultListener<TextSearchResponse?> {
// Return search results upon a successful search.
override fun onSearchResult(results: TextSearchResponse?) {
if (results == null || results.totalCount <= 0) {
return
}
val sites = results.sites
if (sites == null || sites.size == 0) {
return
}
siteArrayList.clear()
for (site in sites) {
siteArrayList.add(site)
}
siteArrayList.addAll(sites)
adapter!!.notifyDataSetChanged()
}
// Return the result code and description upon a search exception.
override fun onSearchError(status: SearchStatus) {
Log.i("TAG", "Error : " + status.errorCode + " " + status.errorMessage)
}
}
// Call the keyword search API.
searchService!!.textSearch(request, resultListener)
} catch (e: UnsupportedEncodingException) {
e.printStackTrace()
}
}
fun nearByPlacesSearch(newText: String?) {
try {
val key = URLEncoder.encode(Constants.API_KEY, "UTF-8")
// Instantiate the SearchService object.
searchService = SearchServiceFactory.create(context, key)
// Create a request body.
val request = NearbySearchRequest()
if (locationResult != null) {
val location = Coordinate(
locationResult!!.lastHWLocation.latitude,
locationResult!!.lastHWLocation.longitude
)
request.location = location
}
request.query = newText
request.radius = 1000
request.hwPoiType = HwLocationType.ADDRESS
request.language = "en"
request.pageIndex = 1
request.pageSize = 5
request.strictBounds = false
// Create a search result listener.
val resultListener: SearchResultListener<NearbySearchResponse?> =
object : SearchResultListener<NearbySearchResponse?> {
// Return search results upon a successful search.
override fun onSearchResult(results: NearbySearchResponse?) {
if (results == null || results.totalCount <= 0) {
return
}
val sites = results.sites
if (sites == null || sites.size == 0) {
return
}
siteArrayList.clear()
for (site in sites) {
siteArrayList.add(site)
}
siteArrayList.addAll(sites)
adapter!!.notifyDataSetChanged()
}
// Return the result code and description upon a search exception.
override fun onSearchError(status: SearchStatus) {
Log.i("TAG", "Error : " + status.errorCode + " " + status.errorMessage)
}
}
// Call the nearby place search API.
searchService!!.nearbySearch(request, resultListener)
} catch (e: Exception) {
e.printStackTrace()
}
}
}
RequestLocationData.kt
Java:
package com.huawei.hms.knowmyboard.dtse.activity.util
import android.Manifest
import com.huawei.hms.knowmyboard.dtse.activity.viewmodel.LoginViewModel
import android.app.Activity
import android.content.Context
import android.os.Build
import android.content.pm.PackageManager
import android.os.Looper
import android.location.Geocoder
import android.util.Log
import androidx.annotation.RequiresApi
import androidx.core.app.ActivityCompat
import androidx.fragment.app.FragmentActivity
import com.huawei.hms.location.*
import java.io.IOException
import java.lang.StringBuilder
import java.util.*
class RequestLocationData(
context: Context?,
activity: FragmentActivity?,
loginViewModel: LoginViewModel?
) {
private var settingsClient: SettingsClient? = null
private var isLocationSettingSuccess = 0
private var myLocationRequest: LocationRequest? = null
// Define a fusedLocationProviderClient object.
private var fusedLocationProviderClient: FusedLocationProviderClient? = null
private var myLocationCallback: LocationCallback? = null
var context: Context? = null
var activity: Activity? = null
private var locationResult: LocationResult? = null
var loginViewModel: LoginViewModel? = null
fun initFusionLocationProviderClint() {
// Instantiate the fusedLocationProviderClient object.
fusedLocationProviderClient = LocationServices.getFusedLocationProviderClient(activity)
this.settingsClient = LocationServices.getSettingsClient(activity)
}
fun checkDeviceLocationSettings() {
val builder = LocationSettingsRequest.Builder()
myLocationRequest = LocationRequest()
builder.addLocationRequest(myLocationRequest)
val locationSettingsRequest = builder.build()
// Check the device location settings.
settingsClient!!.checkLocationSettings(locationSettingsRequest) // Define the listener for success in calling the API for checking device location settings.
.addOnSuccessListener { locationSettingsResponse: LocationSettingsResponse ->
val locationSettingsStates = locationSettingsResponse.locationSettingsStates
val stringBuilder = StringBuilder()
// Check whether the location function is enabled.
stringBuilder.append(",\nisLocationUsable=")
.append(locationSettingsStates.isLocationUsable)
// Check whether HMS Core (APK) is available.
stringBuilder.append(",\nisHMSLocationUsable=")
.append(locationSettingsStates.isHMSLocationUsable)
Log.i(TAG, "checkLocationSetting onComplete:$stringBuilder")
// Set the location type.
myLocationRequest!!.priority = LocationRequest.PRIORITY_HIGH_ACCURACY
// Set the number of location updates to 1.
myLocationRequest!!.numUpdates = 1
isLocationSettingSuccess = 1
} // Define callback for failure in checking the device location settings.
.addOnFailureListener { e -> Log.i(TAG, "checkLocationSetting onFailure:" + e.message) }
}
@RequiresApi(Build.VERSION_CODES.S)
fun checkPermission() {
// Dynamically apply for required permissions if the API level is 28 or lower.
if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.P) {
Log.i(TAG, "android sdk <= 28 Q")
if (ActivityCompat.checkSelfPermission(
context!!,
Manifest.permission.ACCESS_FINE_LOCATION
) != PackageManager.PERMISSION_GRANTED
&& ActivityCompat.checkSelfPermission(
context!!,
Manifest.permission.ACCESS_COARSE_LOCATION
) != PackageManager.PERMISSION_GRANTED
) {
val strings = arrayOf(
Manifest.permission.CAMERA,
Manifest.permission.MANAGE_MEDIA,
Manifest.permission.MEDIA_CONTENT_CONTROL,
Manifest.permission.ACCESS_FINE_LOCATION,
Manifest.permission.ACCESS_COARSE_LOCATION
)
ActivityCompat.requestPermissions(activity!!, strings, 1)
}
} else {
// Dynamically apply for the android.permission.ACCESS_BACKGROUND_LOCATION permission in addition to the preceding permissions if the API level is higher than 28.
if (ActivityCompat.checkSelfPermission(
activity!!,
Manifest.permission.ACCESS_FINE_LOCATION
) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(
context!!,
Manifest.permission.ACCESS_COARSE_LOCATION
) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(
context!!,
"android.permission.ACCESS_BACKGROUND_LOCATION"
) != PackageManager.PERMISSION_GRANTED
) {
val strings = arrayOf(
Manifest.permission.CAMERA,
Manifest.permission.ACCESS_FINE_LOCATION,
Manifest.permission.ACCESS_COARSE_LOCATION,
Manifest.permission.MEDIA_CONTENT_CONTROL,
Manifest.permission.MANAGE_MEDIA,
"android.permission.ACCESS_BACKGROUND_LOCATION"
)
ActivityCompat.requestPermissions(activity!!, strings, 2)
}
}
}
fun refreshLocation(): LocationResult? {
Log.d(TAG, "Refreshing location")
if (isLocationSettingSuccess == 1) {
myLocationCallback = object : LocationCallback() {
private var locationResult: LocationResult? = null
override fun onLocationResult(locationResult: LocationResult) {
if (locationResult != null) {
// Gson gson = new Gson();
//Log.d(TAG, " Location data :" + locationResult.getLastLocation().getLatitude() + " : " + locationResult.getLastLocation().getLongitude());
//Log.d(TAG, " Location data :" + gson.toJson(locationResult.getLastHWLocation()));
//Log.d(TAG, " Location data :" + locationResult.getLastHWLocation().getCountryName());
Log.d(TAG, " Location data :" + locationResult.lastHWLocation.latitude)
Log.d(TAG, " Location data :" + locationResult.lastHWLocation.longitude)
// binding.textDetected.setText("Latitude " + locationResult.getLastHWLocation().getLatitude() + " Longitude " + locationResult.getLastHWLocation().getLongitude());
//getGeoCoderValues(locationResult.getLastHWLocation().getLatitude(),locationResult.getLastHWLocation().getLongitude());
this.locationResult = locationResult
loginViewModel!!.setLocationResult(locationResult)
}
}
}
fusedLocationProviderClient!!.requestLocationUpdates(
myLocationRequest,
myLocationCallback,
Looper.getMainLooper()
)
} else {
Log.d(TAG, "Failed to get location settings")
}
return locationResult
}
fun disableLocationData() {
fusedLocationProviderClient!!.disableBackgroundLocation()
fusedLocationProviderClient!!.removeLocationUpdates(myLocationCallback)
}
private fun getGeoCoderValues(latitude: Double, longitude: Double) {
getAddress(context, latitude, longitude)
/* Geocoder geocoder;
List<Address> addresses;
Locale locale = new Locale("en", "IN");
geocoder = new Geocoder(getContext(), locale);
try {
addresses = geocoder.getFromLocation(latitude, longitude, 1); // Here 1 represent max location result to returned, by documents it recommended 1 to 5
Gson gson=new Gson();
Log.d(TAG,"Geo coder :"+gson.toJson(addresses));
String address = addresses.get(0).getAddressLine(0); // If any additional address line present than only, check with max available address lines by getMaxAddressLineIndex()
String city = addresses.get(0).getLocality();
String state = addresses.get(0).getAdminArea();
String country = addresses.get(0).getCountryName();
String postalCode = addresses.get(0).getPostalCode();
String knownName = addresses.get(0).getFeatureName();
} catch (IOException e) {
e.printStackTrace();
Log.e(TAG,"Error while fetching Geo coder :"+e.getMessage());
}*/
/* Locale locale = new Locale("en", "IN");
GeocoderService geocoderService =
LocationServices.getGeocoderService(getActivity().getBaseContext(), locale);
// Request reverse geocoding.
GetFromLocationRequest getFromLocationRequest = new GetFromLocationRequest(latitude, longitude, 5);
// Initiate reverse geocoding.
geocoderService.getFromLocation(getFromLocationRequest)
.addOnSuccessListener(hwLocation -> {
Gson gson=new Gson();
Log.d(TAG,"Geo coder :"+gson.toJson(hwLocation));
})
.addOnFailureListener(e -> {
Log.e(TAG,"Error while fetching Geo coder :"+e.getMessage());
});*/
}
companion object {
var TAG = "TAG"
fun getAddress(context: Context?, LATITUDE: Double, LONGITUDE: Double) {
//Set Address
try {
val geocoder = Geocoder(context, Locale.getDefault())
val addresses = geocoder.getFromLocation(LATITUDE, LONGITUDE, 1)
if (addresses != null && addresses.size > 0) {
val address =
addresses[0].getAddressLine(0) // If any additional address line present than only, check with max available address lines by getMaxAddressLineIndex()
val city = addresses[0].locality
val state = addresses[0].adminArea
val country = addresses[0].countryName
val postalCode = addresses[0].postalCode
val knownName = addresses[0].featureName // Only if available else return NULL
Log.d(TAG, "getAddress: address$address")
Log.d(TAG, "getAddress: city$city")
Log.d(TAG, "getAddress: state$state")
Log.d(TAG, "getAddress: postalCode$postalCode")
Log.d(TAG, "getAddress: knownName$knownName")
}
} catch (e: IOException) {
e.printStackTrace()
Log.e(TAG, "Error while fetching Geo coder :" + e.message)
}
}
}
init {
[email protected] = context
[email protected] = activity
[email protected] = loginViewModel
}
}
navigation_graph.xml
XML:
<?xml version="1.0" encoding="utf-8"?>
<navigation 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:id="@+id/navigation_graph"
app:startDestination="@id/loginFragment">
<fragment
android:id="@+id/loginFragment"
android:name="com.huawei.hms.knowmyboard.dtse.activity.fragments.LoginFragment"
android:label="LoginFragment"/>
<fragment
android:id="@+id/mainFragment"
android:name="com.huawei.hms.knowmyboard.dtse.activity.fragments.MainFragment"
android:label="MainFragment"/>
<fragment
android:id="@+id/searchFragment"
android:name="com.huawei.hms.knowmyboard.dtse.activity.fragments.SearchFragment"
android:label="fragment_search"
tools:layout="@layout/fragment_search" />
</navigation>
bottom_navigation_menu.xml
XML:
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<item
android:id="@+id/searchFragment"
android:icon="@android:drawable/ic_menu_search"
android:title="@string/search" />
<item
android:id="@+id/loginFragment"
android:icon="@android:drawable/ic_menu_agenda"
android:title="Home" />
<item
android:id="@+id/mainFragment"
app:showAsAction="always"
android:icon="@android:drawable/ic_menu_gallery"
android:title="Gallery" />
</menu>
Result
{
"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"
}
Tricks and Tips
Makes sure that agconnect-services.json file added.
Make sure required dependencies are added
Make sure that service is enabled in AGC
Enable data binding in gradle.build file
Make sure bottom navigation id's should be same as fragment id's in navigation graph
Conclusion
In this article, we have learnt how to integrate Huawei Site Kit, Map kit, Location kit in Android application KnowMyBoard. Hoping that the Map kit capabilities are helpful to you as well, like this sample, you can make use of Site kit as per your requirement.
Reference
Map Kit – Training video
Site Kit – Training video
Related
Hi.
Right now i try to acess my Media Data. I looked at the datasheets from the official google site and the example. Sadly i don't get how i properly implement the functions. Or is my root_id just wrong?
Grettings Losspost
My MediaPlaybackService:
Code:
package com.name.mediabrowsertest
import android.media.MediaDescription
import android.media.MediaMetadata
import android.media.browse.MediaBrowser
import android.media.session.MediaSession
import android.os.Build
import android.os.Bundle
import android.provider.MediaStore
import android.support.annotation.RequiresApi
import android.support.v4.media.MediaBrowserCompat
import android.support.v4.media.MediaBrowserServiceCompat
import android.support.v4.media.MediaDescriptionCompat
import android.support.v4.media.MediaMetadataCompat
import android.support.v4.media.session.MediaSessionCompat
import android.support.v4.media.session.PlaybackStateCompat
import android.util.Log
class MediaPlaybackService: MediaBrowserServiceCompat(){
//private val MY_MEDIA_ROOT_ID = "MediaStore.Audio.Media.EXTERNAL_CONTENT_URI"
private val MY_MEDIA_ROOT_ID ="root"
private lateinit var mMediaSession: MediaSessionCompat
private lateinit var mStateBuilder : PlaybackStateCompat.Builder
private var MySessionCallback =object : MediaSessionCompat.Callback() {
override fun onPause() {
super.onPause()
}
override fun onPlay() {
super.onPlay()
}
}
override fun onCreate() {
super.onCreate()
//Create the MediaSession
mMediaSession = MediaSessionCompat(this,"PLAYER")
//Setting the necessary Flags (Media Buttons)
mMediaSession.setFlags(
MediaSessionCompat.FLAG_HANDLES_MEDIA_BUTTONS or MediaSessionCompat.FLAG_HANDLES_TRANSPORT_CONTROLS)
//Set an inital PlaybackStatewith ACTION_BUTTONS, so Media buttons can start the player
mStateBuilder = PlaybackStateCompat.Builder().setActions(
PlaybackStateCompat.ACTION_PLAY or PlaybackStateCompat.ACTION_PAUSE)
//Set our PLaybackState for the MediaSession
mMediaSession.setPlaybackState(mStateBuilder.build())
//Handles callbacks from Media Controller MySessionCalback is a PlaeHolder
mMediaSession.setCallback(MySessionCallback)
//Set SessionToken so Activites can communicate with it
sessionToken = mMediaSession.sessionToken
}
override fun onLoadChildren(parentId: String, result: Result<MutableList<MediaBrowserCompat.MediaItem>>) {
var mediaItems:ArrayList<MediaBrowserCompat.MediaItem> = ArrayList()
var builder = MediaDescriptionCompat.Builder()
builder.setTitle("Media Items")
var mediaItem = MediaBrowserCompat.MediaItem(builder.build(),MediaBrowser.MediaItem.FLAG_PLAYABLE)
// for (metadata in medi.values()) {
// result.add(
// MediaBrowserCompat.MediaItem(
// metadata.getDescription(), MediaBrowserCompat.MediaItem.FLAG_PLAYABLE))
//}
Log.i("mediaItem",mediaItem.mediaId)
mediaItems.add(mediaItem)
var res = mediaItems.toMutableList()
for (x in res){
Log.i("musik",x.toString())
}
result.sendResult(res)
}
override fun onGetRoot(clientPackageName: String, clientUid: Int, rootHints: Bundle?): BrowserRoot? {
return BrowserRoot(MY_MEDIA_ROOT_ID,null)
}
}
And my Main Activity:
Code:
package com.name.mediabrowsertest
import android.content.ComponentName
import android.content.Context
import android.content.res.Configuration
import android.media.AudioManager
import android.media.MediaDataSource
import android.media.session.MediaController
import android.os.Build
import android.support.v7.app.AppCompatActivity
import android.os.Bundle
import android.provider.MediaStore
import android.support.annotation.RequiresApi
import android.support.v4.media.MediaBrowserCompat
import android.support.v4.media.MediaBrowserServiceCompat
import android.support.v4.media.MediaMetadataCompat
import android.support.v4.media.session.MediaControllerCompat
import android.support.v4.media.session.PlaybackStateCompat
import android.util.Log
import android.view.View
import android.widget.ImageView
class MainActivity : AppCompatActivity() {
private lateinit var mMediaBrowser: MediaBrowserCompat
fun buildTransportControls(){
mMediaBrowser.subscribe(mMediaBrowser.root,object: MediaBrowserCompat.SubscriptionCallback(){})
var mPlayPause = findViewById<ImageView>(R.id.imageView)
//Attach listen to button
mPlayPause.setOnClickListener(object: View.OnClickListener {
override fun onClick(v : View ){
var pbSate = MediaControllerCompat.getMediaController([email protected]).playbackState.playbackState
if(pbSate == PlaybackStateCompat.STATE_PLAYING){
MediaControllerCompat.getMediaController([email protected]).transportControls.pause()
}else{
MediaControllerCompat.getMediaController([email protected]).transportControls.playFromMediaId(MediaBrowserCompat.EXTRA_MEDIA_ID,null)
MediaControllerCompat.getMediaController([email protected]).transportControls.play()
//MediaControllerCompat.getMediaController([email protected]).transportControls.playFromMediaId()
}
}
})
var mediaController = MediaControllerCompat.getMediaController([email protected]ctivity)
//Show Init state
var metadat = mediaController.metadata
var pbState = mediaController.playbackState
//Register Callback to stay synced
mediaController.registerCallback(controllerCallback)
}
val controllerCallback = object : MediaControllerCompat.Callback() {
override fun onMetadataChanged(metadat:MediaMetadataCompat){
Log.i("Musik",metadat.toString())
}
override fun onPlaybackStateChanged(state :PlaybackStateCompat){}
}
private val mConnectionCallbacks = object : MediaBrowserCompat.ConnectionCallback() {
override fun onConnected() {
Log.i("Connection","Connecting")
// Get the token for the MediaSession
val token = mMediaBrowser.sessionToken
// Create a MediaControllerCompat
val mediaController = MediaControllerCompat([email protected],token)
// Save the controller
MediaControllerCompat.setMediaController([email protected], mediaController)
// Finish building the UI
buildTransportControls()
}
override fun onConnectionSuspended() {
// The Service has crashed. Disable transport controls until it automatically reconnects
Log.i("ERROR","Connection Suspended")
}
override fun onConnectionFailed() {
// The Service has refused our connection
Log.i("ERROR","Connection Failed")
}
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
Log.i("Hello World","Hello")
//Create MediaBrowser Service
mMediaBrowser = MediaBrowserCompat(this,
ComponentName(this, MediaPlaybackService::class.java),
mConnectionCallbacks,
null)
Log.i("Hello World","Hello2")
}
override fun onStart() {
super.onStart()
mMediaBrowser.connect()
}
override fun onResume() {
super.onResume()
volumeControlStream = AudioManager.STREAM_MUSIC
}
override fun onStop() {
super.onStop()
if(MediaControllerCompat.getMediaController([email protected]) != null){
MediaControllerCompat.getMediaController([email protected]).unregisterCallback(controllerCallback)
}
mMediaBrowser.disconnect()
}
}
Overview
Click to expand...
Click to collapse
In this article, I will create a Doctor Consult Demo App along with the integration of Huawei Id, Map and Identity Kit. Which provides an easy interface to consult with doctor. Users can choose specific doctors and get the doctor details using Huawei User Address.
By reading this article, you'll get an overview of HMS Core Identity, Map and Account Kit, including its functions, open capabilities and business value.
HMS Core Map Service Introduction
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.
Prerequisite
Huawei Phone EMUI 3.0 or later.
Non-Huawei phones Android 4.4 or later (API level 19 or higher).
Android Studio.
AppGallery Account.
App Gallery Integration process
Sign In and Create or Choose a project on AppGallery Connect portal.
Navigate to Project settings and download the configuration file.
Navigate to General Information, and then provide Data Storage location.
App Development
Create A New Project.
Configure Project Gradle.
Configure App Gradle.
apply plugin: 'com.android.application'apply plugin: 'com.huawei.agconnect'android { compileSdkVersion 30 buildToolsVersion "29.0.3" defaultConfig { applicationId "com.hms.doctorconsultdemo" minSdkVersion 27 targetSdkVersion 30 versionCode 1 versionName "1.0" testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" } buildTypes { release { minifyEnabled false proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' } } compileOptions { sourceCompatibility JavaVersion.VERSION_1_8 targetCompatibility JavaVersion.VERSION_1_8 }}dependencies { implementation fileTree(dir: "libs", include: ["*.jar"]) implementation 'androidx.appcompat:appcompat:1.3.0' implementation 'androidx.constraintlayout:constraintlayout:2.0.4' implementation 'androidx.cardview:cardview:1.0.0' testImplementation 'junit:junit:4.12' androidTestImplementation 'androidx.test.ext:junit:1.1.2' androidTestImplementation 'androidx.test.espresso:espresso-core:3.3.0' //noinspection GradleCompatible implementation 'com.android.support:recyclerview-v7:27.0.2' implementation 'androidx.navigation:navigation-ui:2.1.0' implementation 'androidx.lifecycle:lifecycle-extensions:2.2.0' implementation 'com.huawei.hms:identity:5.3.0.300' //Dagger implementation 'com.google.dagger:dagger:2.13' annotationProcessor 'com.google.dagger:dagger-compiler:2.13' //noinspection GradleCompatible implementation 'com.android.support:cardview-v7:28.0.0' implementation 'com.android.support:support-v4:28.0.0' implementation 'com.google.android.material:material:1.2.0' implementation "com.google.code.gson:gson:2.8.5" implementation('com.huawei.hms:hwid:4.0.4.300') implementation "com.squareup.okhttp3khttp:3.14.2" implementation 'com.squareup.okiokio:1.14.1' implementation 'com.github.bumptech.glide:glide:4.9.0' implementation 'com.huawei.hms:ads-lite:13.4.30.307' implementation 'com.huawei.hms:hianalytics:5.0.3.300' //map// implementation 'com.huawei.hms:maps:4.0.0.301' implementation 'com.huawei.hms:maps:5.0.1.300' //site implementation 'com.huawei.hms:site:4.0.0.300' //location implementation 'com.huawei.hms:location:4.0.3.301' implementation 'com.squareup.retrofit2:retrofit:2.5.0' implementation 'com.squareup.retrofit2:converter-gson:2.5.0' implementation "com.squareup.retrofit2:adapter-rxjava2:2.6.2" implementation 'io.reactivex:rxjava:1.3.0' implementation 'io.reactivex:rxandroid:1.2.1' implementation 'com.android.support:multidex:1.0.3' implementation 'com.squareup.okhttp3:logging-interceptor:4.2.2' // RxAndroid implementation 'io.reactivex.rxjava2:rxjava:2.2.8' implementation 'io.reactivex.rxjava2:rxandroid:2.1.1' implementation 'com.huawei.hms:awareness:1.0.4.301' implementation 'com.huawei.hms:dtm-api:5.0.2.300' implementation 'com.huawei.agconnect:agconnect-remoteconfig:1.3.1.300' implementation 'com.huawei.agconnect:agconnect-crash:1.4.1.300' implementation "com.huawei.agconnect:agconnect-appmessaging:1.4.1.300" implementation 'com.huawei.agconnect:agconnect-auth:1.4.1.300'}
Configure AndroidManifest.xml.
Create Activity class with XML UI.
DirectionActivity:
JavaScript:
package com.hms.doctorconsultdemo.map;
import android.Manifest;
import android.content.Intent;
import android.content.IntentSender;
import android.content.pm.PackageManager;
import android.graphics.Color;
import android.graphics.drawable.ColorDrawable;
import android.location.Location;
import android.os.Build;
import android.os.Bundle;
import android.os.Looper;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import androidx.appcompat.app.ActionBar;
import androidx.appcompat.app.AppCompatActivity;
import androidx.appcompat.widget.Toolbar;
import androidx.cardview.widget.CardView;
import androidx.core.app.ActivityCompat;
import androidx.lifecycle.ViewModelProviders;
import com.google.android.material.card.MaterialCardView;
import com.hms.doctorconsultdemo.BookAppointmentActivity;
import com.hms.doctorconsultdemo.R;
import com.hms.doctorconsultdemo.map.apiconnector.polylineBody.Destination;
import com.hms.doctorconsultdemo.map.apiconnector.polylineBody.Origin;
import com.hms.doctorconsultdemo.map.apiconnector.polylineBody.PolylineBody;
import com.hms.doctorconsultdemo.map.apiconnector.polylineResponse.Paths;
import com.hms.doctorconsultdemo.map.apiconnector.polylineResponse.Polyline;
import com.hms.doctorconsultdemo.map.apiconnector.polylineResponse.PolylineResponse;
import com.hms.doctorconsultdemo.map.apiconnector.polylineResponse.Routes;
import com.hms.doctorconsultdemo.map.apiconnector.polylineResponse.Steps;
import com.huawei.agconnect.remoteconfig.AGConnectConfig;
import com.huawei.hmf.tasks.OnFailureListener;
import com.huawei.hms.common.ApiException;
import com.huawei.hms.common.ResolvableApiException;
import com.huawei.hms.location.FusedLocationProviderClient;
import com.huawei.hms.location.LocationAvailability;
import com.huawei.hms.location.LocationCallback;
import com.huawei.hms.location.LocationRequest;
import com.huawei.hms.location.LocationResult;
import com.huawei.hms.location.LocationServices;
import com.huawei.hms.location.LocationSettingsRequest;
import com.huawei.hms.location.LocationSettingsStatusCodes;
import com.huawei.hms.location.SettingsClient;
import com.huawei.hms.maps.CameraUpdateFactory;
import com.huawei.hms.maps.HuaweiMap;
import com.huawei.hms.maps.MapView;
import com.huawei.hms.maps.OnMapReadyCallback;
import com.huawei.hms.maps.SupportMapFragment;
import com.huawei.hms.maps.model.LatLng;
import com.huawei.hms.maps.model.MapStyleOptions;
import com.huawei.hms.maps.model.Marker;
import com.huawei.hms.maps.model.MarkerOptions;
import com.huawei.hms.maps.model.PolylineOptions;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class DirectionActivity extends AppCompatActivity implements OnMapReadyCallback {
public static final String TAG = "DirectionActivity";
private static final String MAPVIEW_BUNDLE_KEY = "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX";
private HuaweiMap hmap;
private MapView mMapView;
private Marker mMarker;
private List<LatLng> latLngList;
private MapApiViewModel mapApiViewModel;
private CardView cardView;
private LocationCallback mLocationCallback;
private LocationRequest mLocationRequest;
private FusedLocationProviderClient fusedLocationProviderClient;
private SettingsClient settingsClient;
private PolylineBody polylineBody;
private Button btnBooking;
private Map<String, Object> remoteConfigMap;
private AGConnectConfig config;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
init();
remoteConfigMap = new HashMap<>();
config = AGConnectConfig.getInstance();
remoteConfigMap.put("mapstyle", "light");
config.applyDefault(remoteConfigMap);
SupportMapFragment mapFragment = (SupportMapFragment) getSupportFragmentManager().findFragmentById(R.id.mapView);
mMapView = findViewById(R.id.mapView);
Bundle mapViewBundle = null;
if (savedInstanceState != null) {
mapViewBundle = savedInstanceState.getBundle(MAPVIEW_BUNDLE_KEY);
}
mMapView.onCreate(mapViewBundle);
mMapView.getMapAsync(DirectionActivity.this);
}
private void init() {
setContentView(R.layout.activity_direction);
cardView = findViewById(R.id.card_map);
btnBooking = findViewById(R.id.btn_book_trip);
btnBooking.setOnClickListener(view -> {
Intent intent = new Intent(this, BookAppointmentActivity.class);
startActivity(intent);
});
Toolbar toolbar = findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
getSupportActionBar().setDisplayShowHomeEnabled(true);
Bundle extras = getIntent().getExtras();
if (extras != null) {
String name = extras.getString("name");
String orgLat = extras.getString("orgLat");
String orgLong = extras.getString("orgLong");
String desLat = extras.getString("desLat");
String desLong = extras.getString("desLong");
boolean tripDisplay = extras.getBoolean("isTrip");
if (!tripDisplay) {
cardView.setVisibility(View.GONE);
} else {
cardView.setVisibility(View.VISIBLE);
}
setTitle(name);
setLatLong(orgLat, orgLong, desLat, desLong);
}
mapApiViewModel = ViewModelProviders.of(this).get(MapApiViewModel.class);
fusedLocationProviderClient = LocationServices.getFusedLocationProviderClient(this);
settingsClient = LocationServices.getSettingsClient(this);
mLocationRequest = new LocationRequest();
mLocationRequest.setInterval(10000);
mLocationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
if (null == mLocationCallback) {
mLocationCallback = new LocationCallback() {
@Override
public void onLocationResult(LocationResult locationResult) {
if (locationResult != null) {
List<Location> locations = locationResult.getLocations();
if (!locations.isEmpty()) {
for (Location location : locations) {
Log.i(TAG,
"onLocationResult location[Longitude,Latitude,Accuracy]:" + location.getLongitude()
+ "," + location.getLatitude() + "," + location.getAccuracy());
}
}
}
}
@Override
public void onLocationAvailability(LocationAvailability locationAvailability) {
if (locationAvailability != null) {
boolean flag = locationAvailability.isLocationAvailable();
Log.i(TAG, TAG + flag);
}
}
};
}
// check location permisiion
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 = {Manifest.permission.ACCESS_FINE_LOCATION,
Manifest.permission.ACCESS_COARSE_LOCATION,
"android.permission.ACCESS_BACKGROUND_LOCATION"};
ActivityCompat.requestPermissions(this, strings, 2);
}
}
}
@Override
protected void onStart() {
super.onStart();
mMapView.onStart();
}
@Override
protected void onResume() {
super.onResume();
mMapView.onResume();
}
@Override
protected void onPause() {
super.onPause();
mMapView.onPause();
}
@Override
protected void onStop() {
super.onStop();
mMapView.onStop();
}
@Override
protected void onDestroy() {
super.onDestroy();
mMapView.onDestroy();
}
@Override
public void onMapReady(HuaweiMap map) {
hmap = map;
hmap.setMyLocationEnabled(true);
hmap.setTrafficEnabled(true);
hmap.getUiSettings().setRotateGesturesEnabled(true);
hmap.getUiSettings().setCompassEnabled(false);
mapApiViewModel.getPolylineLiveData(getPolylineBody()).observe(this, result -> {
Log.d(TAG, result.toString());
getPolylineData(result);
});
addHMSRemoteConfigListner();
}
private PolylineBody getPolylineBody() {
return polylineBody;
}
private void setLatLong(String orgLat, String orgLong, String desLat, String desLong) {
polylineBody = new PolylineBody();
Origin origin = new Origin();
origin.setLat(orgLat);
origin.setLng(orgLong);
Destination destination = new Destination();
destination.setLat(desLat);
destination.setLng(desLong);
polylineBody.setDestination(destination);
polylineBody.setOrigin(origin);
}
public void getPolylineData(PolylineResponse polylineResponse) {
List<Routes> routesList = polylineResponse.getRoutes();
List<Paths> paths = new ArrayList<>();
List<Steps> steps = new ArrayList<>();
List<Polyline> polylines = new ArrayList<>();
latLngList = new ArrayList<>();
for (int x = 0; x < routesList.size(); x++) {
for (Paths paths1 : routesList.get(x).getPaths()) {
paths.add(paths1);
}
for (int y = 0; y < paths.size(); y++) {
for (Steps step :
paths.get(y).getSteps()) {
steps.add(step);
}
}
for (int i = 0; i < steps.size(); i++) {
for (Polyline polyline :
steps.get(i).getPolyline()) {
polylines.add(polyline);
}
}
}
for (int i = 0; i < polylines.size(); i++) {
latLngList.add(new LatLng(Double.valueOf(polylines.get(i).getLat())
, Double.valueOf(polylines.get(i).getLng())));
}
hmap.animateCamera(CameraUpdateFactory.newLatLngZoom(latLngList.get(0), 12.0f));
hmap.addMarker(new MarkerOptions().position(latLngList.get(0)));
hmap.addPolyline(new PolylineOptions()
.addAll(latLngList)
.color(Color.BLUE)
.width(3));
}
private void requestLocationUpdatesWithCallback() {
try {
LocationSettingsRequest.Builder builder = new LocationSettingsRequest.Builder();
builder.addLocationRequest(mLocationRequest);
LocationSettingsRequest locationSettingsRequest = builder.build();
settingsClient.checkLocationSettings(locationSettingsRequest)
.addOnSuccessListener(locationSettingsResponse -> {
Log.i(TAG, "check location settings success");
fusedLocationProviderClient
.requestLocationUpdates(mLocationRequest, mLocationCallback, Looper.getMainLooper())
.addOnSuccessListener(aVoid -> Log.i(TAG, "requestLocationUpdatesWithCallback onSuccess"))
.addOnFailureListener(new OnFailureListener() {
@Override
public void onFailure(Exception e) {
Log.e(TAG,
"requestLocationUpdatesWithCallback onFailure:" + e.getMessage());
}
});
})
.addOnFailureListener(e -> {
Log.e(TAG, "checkLocationSetting onFailure:" + e.getMessage());
int statusCode = ((ApiException) e).getStatusCode();
switch (statusCode) {
case LocationSettingsStatusCodes.RESOLUTION_REQUIRED:
try {
ResolvableApiException rae = (ResolvableApiException) e;
rae.startResolutionForResult(DirectionActivity.this, 0);
} catch (IntentSender.SendIntentException sie) {
Log.e(TAG, "PendingIntent unable to execute request.");
}
break;
}
});
} catch (Exception e) {
Log.e(TAG, "requestLocationUpdatesWithCallback exception:" + e.getMessage());
}
}
@Override
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
if (requestCode == 1) {
if (grantResults.length > 1 && grantResults[0] == PackageManager.PERMISSION_GRANTED
&& grantResults[1] == PackageManager.PERMISSION_GRANTED) {
Log.i(TAG, "onRequestPermissionsResult: apply LOCATION PERMISSION successful");
} else {
Log.i(TAG, "onRequestPermissionsResult: apply LOCATION PERMISSSION failed");
}
}
if (requestCode == 2) {
if (grantResults.length > 2 && grantResults[2] == PackageManager.PERMISSION_GRANTED
&& grantResults[0] == PackageManager.PERMISSION_GRANTED
&& grantResults[1] == PackageManager.PERMISSION_GRANTED) {
Log.i(TAG, "onRequestPermissionsResult: apply ACCESS_BACKGROUND_LOCATION successful");
} else {
Log.i(TAG, "onRequestPermissionsResult: apply ACCESS_BACKGROUND_LOCATION failed");
}
}
}
private void addHMSRemoteConfigListner() {
config.fetch(5).addOnSuccessListener(configValues -> {
config.apply(configValues);
MapStyleOptions mapStyleOptions;
String style = config.getValueAsString("mapstyle");
String colorPrimary = config.getValueAsString("primarycolor");
Log.d(TAG, "HMS color : " + colorPrimary);
ActionBar actionBar = getSupportActionBar();
actionBar.setBackgroundDrawable(new ColorDrawable(Color.parseColor(colorPrimary)));
if (style.equalsIgnoreCase("dark")) {
mapStyleOptions = MapStyleOptions.loadRawResourceStyle(DirectionActivity.this, R.raw.mapstyle_night);
hmap.setMapStyle(mapStyleOptions);
} else if (style.equalsIgnoreCase("light")) {
mapStyleOptions = MapStyleOptions.loadRawResourceStyle(DirectionActivity.this, R.raw.mapstyle_day);
hmap.setMapStyle(mapStyleOptions);
}
}).addOnFailureListener((OnFailureListener) e -> {
Log.d(TAG, e.getMessage());
});
}
}
App Build Result
{
"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"
}
Tips and Tricks
Map data of Map Kit does not cover the Chinese mainland. Therefore, the Map SDK for Android, Map SDK (Java) for HarmonyOS, JavaScript API, Static Map API, and Directions API of Map Kit are unavailable in the Chinese mainland. For details about locations where the services are available.
The map zoom icons flash on the map on devices running Android 8 or earlier before the map is loaded. (This issue occurs at a low probability in Android 8, but does not occur in versions later than Android 8.)
Layout file (XML file): Set uiZoomControls to false.
Code file: Set the parameter of the HuaweiMapOptions.zoomControlsEnabled(boolean isZoomControlsEnabled) method to false.
Conclusion
In this article, we have learned how to integrate HMS Core Identity and Map in Android application. After completely read this article user can easily implement Huawei User Address and Map APIs by HMS Core Identity, so that User can consult with doctor using Huawei User Address and redirect to Doctor Location.
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.
References
HMS Identity Docs: https://developer.huawei.com/consumer/en/hms/huawei-identitykit/
https://developer.huawei.com/consum...des/android-sdk-introduction-0000001061991291
HMS Training Videos -
https://developer.huawei.com/consumer/en/training/
{
"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"
}
IntroductionIn this article, we will learn how to integrate the Huawei ML kit and Location kit into the Android application KnowMyBoard.
If you are new to this series follow the below article.
Intermediate: Integration of Huawei Account Kit and Analytics Kit in Android App KnowMyBoard Part -1
ML Kit provides an app to easily leverage Huawei's long-term proven expertise in machine learning to support diverse artificial intelligence (AI) applications throughout a wide range of industries.
ML kit provides various services, in this application, we will be integrating its text-related service like text recognition, text detection, and text translation services, which helps in achieving the goal of the application.
Location kit SDK for Android offers location-related APIs for Android apps. These APIs mainly relate to 6 functions fused location, activity identification, geofence, high-precision location, indoor location, and geocoding. This mode is applicable to mobile phones and Huawei tablets. We are using the Location kit to get the location of the user.
Hardware Requirements
A computer (desktop or laptop) running Windows 10.
Android phone (with the USB cable), which is used for debugging.
Java JDK 1.8 or later.
Android Studio software or Visual Studio or Code installed.
HMS Core (APK) 4.X or later
Integration steps
Step 1. Huawei developer account and complete identity verification in Huawei developer website, refer to register Huawei ID.
Step 2. Create a project in AppGallery Connect
Step 3. Adding HMS Core SDK
Let's start coding
MainActivity.kt
Java:
package com.huawei.hms.knowmyboard.dtse.activity.view
import com.huawei.hms.knowmyboard.dtse.activity.app.MyApplication.Companion.activity
import androidx.appcompat.app.AppCompatActivity
import com.huawei.hms.knowmyboard.dtse.activity.viewmodel.LoginViewModel
import com.huawei.hms.mlsdk.text.MLTextAnalyzer
import android.graphics.Bitmap
import com.huawei.hms.mlsdk.langdetect.local.MLLocalLangDetector
import com.huawei.hms.mlsdk.translate.local.MLLocalTranslator
import android.app.ProgressDialog
import android.os.Bundle
import androidx.lifecycle.ViewModelProvider
import android.content.Intent
import com.huawei.hms.support.account.AccountAuthManager
import com.google.gson.Gson
import com.huawei.hms.common.ApiException
import android.provider.MediaStore
import com.huawei.hms.mlsdk.common.MLFrame
import com.huawei.hms.mlsdk.text.MLText
import com.huawei.hmf.tasks.OnSuccessListener
import com.huawei.hms.mlsdk.langdetect.MLLangDetectorFactory
import com.huawei.hms.mlsdk.langdetect.local.MLLocalLangDetectorSetting
import com.huawei.hmf.tasks.OnFailureListener
import android.content.DialogInterface
import android.net.Uri
import android.util.Log
import androidx.appcompat.app.AlertDialog
import com.huawei.hms.knowmyboard.dtse.R
import com.huawei.hms.knowmyboard.dtse.activity.model.UserData
import com.huawei.hms.mlsdk.common.MLApplication
import com.huawei.hms.mlsdk.translate.local.MLLocalTranslateSetting
import com.huawei.hms.mlsdk.translate.MLTranslatorFactory
import com.huawei.hms.mlsdk.model.download.MLModelDownloadStrategy
import com.huawei.hms.mlsdk.model.download.MLModelDownloadListener
import com.huawei.hms.mlsdk.text.MLLocalTextSetting
import com.huawei.hms.mlsdk.MLAnalyzerFactory
import java.io.IOException
import java.lang.Exception
import java.util.ArrayList
class MainActivity() : AppCompatActivity() {
var loginViewModel: LoginViewModel? = null
private var mTextAnalyzer: MLTextAnalyzer? = null
var imagePath: Uri? = null
var bitmap: Bitmap? = null
var result = ArrayList<String>()
var myLocalLangDetector: MLLocalLangDetector? = null
var myLocalTranslator: MLLocalTranslator? = null
var textRecognized: String? = null
var progressDialog: ProgressDialog? = null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
loginViewModel = ViewModelProvider(this).get(LoginViewModel::class.java)
activity = this
progressDialog = ProgressDialog(this)
progressDialog!!.setCancelable(false)
}
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
// Process the authorization result to obtain the authorization code from AuthAccount.
super.onActivityResult(requestCode, resultCode, data)
if (requestCode == 8888) {
val authAccountTask = AccountAuthManager.parseAuthResultFromIntent(data)
if (authAccountTask.isSuccessful) {
// The sign-in is successful, and the user's ID information and authorization code are obtained.
val authAccount = authAccountTask.result
val userData = UserData()
userData.accessToken = authAccount.accessToken
userData.countryCode = authAccount.countryCode
userData.displayName = authAccount.displayName
userData.email = authAccount.email
userData.familyName = authAccount.familyName
userData.givenName = authAccount.givenName
userData.idToken = authAccount.idToken
userData.openId = authAccount.openId
userData.uid = authAccount.uid
userData.photoUriString = authAccount.avatarUri.toString()
userData.unionId = authAccount.unionId
val gson = Gson()
Log.e("TAG", "sign in success : " + gson.toJson(authAccount))
loginViewModel = ViewModelProvider([email protected]).get(
LoginViewModel::class.java
)
loginViewModel!!.sendData(authAccount.displayName)
progressDialog!!.dismiss()
} else {
// The sign-in failed.
Log.e(
"TAG",
"sign in failed:" + (authAccountTask.exception as ApiException).statusCode
)
progressDialog!!.dismiss()
}
}
if ((requestCode == 2323) && (resultCode == RESULT_OK) && (data != null)) {
progressDialog!!.setMessage("Initializing text detection..")
progressDialog!!.show()
imagePath = data.data
try {
bitmap = MediaStore.Images.Media.getBitmap(this.contentResolver, imagePath)
} catch (e: IOException) {
e.printStackTrace()
Log.e("TAG", " BITMAP ERROR")
}
Log.d("TAG", "Path " + imagePath!!.path)
try {
val selectedBitmap = MediaStore.Images.Media.getBitmap(contentResolver, imagePath)
asyncAnalyzeText(selectedBitmap)
} catch (e: IOException) {
e.printStackTrace()
progressDialog!!.dismiss()
}
}
}
private fun asyncAnalyzeText(bitmap: Bitmap) {
if (mTextAnalyzer == null) {
createMLTextAnalyzer()
}
val frame = MLFrame.fromBitmap(bitmap)
val task = mTextAnalyzer!!.asyncAnalyseFrame(frame)
task.addOnSuccessListener(object : OnSuccessListener<MLText> {
override fun onSuccess(text: MLText) {
progressDialog!!.setMessage("Initializing language detection..")
Log.d("TAG", "#==>" + text.stringValue)
textRecognized = text.stringValue.trim { it <= ' ' }
if (!textRecognized!!.isEmpty()) {
// Create a local language detector.
val factory = MLLangDetectorFactory.getInstance()
val setting =
MLLocalLangDetectorSetting.Factory() // Set the minimum confidence threshold for language detection.
.setTrustedThreshold(0.01f)
.create()
myLocalLangDetector = factory.getLocalLangDetector(setting)
val firstBestDetectTask = myLocalLangDetector?.firstBestDetect(textRecognized)
firstBestDetectTask?.addOnSuccessListener(OnSuccessListener { languageDetected ->
progressDialog!!.setMessage("Initializing text translation..")
// Processing logic for detection success.
Log.d("TAG", "Lang detect :$languageDetected")
textTranslate(languageDetected, textRecognized!!, bitmap)
})?.addOnFailureListener(object : OnFailureListener {
override fun onFailure(e: Exception) {
// Processing logic for detection failure.
Log.e("TAG", "Lang detect error:" + e.message)
}
})
} else {
progressDialog!!.dismiss()
showErrorDialog("Failed to recognize text.")
}
}
}).addOnFailureListener(object : OnFailureListener {
override fun onFailure(e: Exception) {
Log.e("TAG", "#==>" + e.message)
}
})
}
private fun showErrorDialog(msg: String) {
val alertDialog = AlertDialog.Builder(this).create()
alertDialog.setTitle("Error")
alertDialog.setMessage(msg)
alertDialog.setButton(
AlertDialog.BUTTON_POSITIVE,
"OK",
object : DialogInterface.OnClickListener {
override fun onClick(dialog: DialogInterface, which: Int) {
dialog.dismiss()
}
})
alertDialog.show()
}
private fun textTranslate(languageDetected: String, textRecognized: String, uri: Bitmap) {
MLApplication.initialize(application)
MLApplication.getInstance().apiKey =
"DAEDAF48ZIMI4ettQdTfCKlXgaln/E+TO/PrsX+LpP2BubkmED/iC0iVEps5vfx1ol27rHvuwiq64YphpPkGYWbf9La8XjnvC9qhwQ=="
// Create an offline translator.
val setting =
MLLocalTranslateSetting.Factory() // Set the source language code. The ISO 639-1 standard is used. This parameter is mandatory. If this parameter is not set, an error may occur.
.setSourceLangCode(languageDetected) // Set the target language code. The ISO 639-1 standard is used. This parameter is mandatory. If this parameter is not set, an error may occur.
.setTargetLangCode("en")
.create()
myLocalTranslator = MLTranslatorFactory.getInstance().getLocalTranslator(setting)
// Set the model download policy.
val downloadStrategy = MLModelDownloadStrategy.Factory()
.needWifi() // It is recommended that you download the package in a Wi-Fi environment.
.create()
// Create a download progress listener.
val modelDownloadListener: MLModelDownloadListener = object : MLModelDownloadListener {
override fun onProcess(alreadyDownLength: Long, totalLength: Long) {
runOnUiThread(object : Runnable {
override fun run() {
// Display the download progress or perform other operations.
}
})
}
}
myLocalTranslator?.preparedModel(downloadStrategy, modelDownloadListener)
?.addOnSuccessListener(object : OnSuccessListener<Void?> {
override fun onSuccess(aVoid: Void?) {
// Called when the model package is successfully downloaded.
// input is a string of less than 5000 characters.
val task = myLocalTranslator?.asyncTranslate(textRecognized)
// Before translation, ensure that the models have been successfully downloaded.
task?.addOnSuccessListener(object : OnSuccessListener<String> {
override fun onSuccess(translated: String) {
// Processing logic for detection success.
result.clear()
result.add(languageDetected.trim { it <= ' ' })
result.add(textRecognized.trim { it <= ' ' })
result.add(translated.trim { it <= ' ' })
loginViewModel!!.setImage(uri)
loginViewModel!!.setTextRecognized(result)
progressDialog!!.dismiss()
}
})?.addOnFailureListener(object : OnFailureListener {
override fun onFailure(e: Exception) {
// Processing logic for detection failure.
progressDialog!!.dismiss()
}
})
}
})?.addOnFailureListener(object : OnFailureListener {
override fun onFailure(e: Exception) {
// Called when the model package fails to be downloaded.
progressDialog!!.dismiss()
}
})
}
private fun createMLTextAnalyzer() {
val setting = MLLocalTextSetting.Factory()
.setOCRMode(MLLocalTextSetting.OCR_DETECT_MODE)
.create()
mTextAnalyzer = MLAnalyzerFactory.getInstance().getLocalTextAnalyzer(setting)
}
override fun onStop() {
if (myLocalLangDetector != null) {
myLocalLangDetector!!.stop()
}
if (myLocalTranslator != null) {
myLocalTranslator!!.stop()
}
if (progressDialog != null) {
progressDialog!!.dismiss()
}
super.onStop()
}
}
LoginViewModel.kt
Java:
package com.huawei.hms.knowmyboard.dtse.activity.viewmodel
import android.app.Application
import com.huawei.hms.knowmyboard.dtse.activity.app.MyApplication.Companion.activity
import androidx.lifecycle.AndroidViewModel
import com.huawei.hms.support.account.service.AccountAuthService
import androidx.lifecycle.MutableLiveData
import android.graphics.Bitmap
import android.util.Log
import android.view.View
import com.huawei.hms.location.LocationResult
import androidx.lifecycle.LiveData
import android.widget.Toast
import com.huawei.hms.support.account.request.AccountAuthParams
import com.huawei.hms.support.account.request.AccountAuthParamsHelper
import com.huawei.hms.support.account.AccountAuthManager
import com.huawei.hms.common.ApiException
import java.util.ArrayList
class LoginViewModel(application: Application) : AndroidViewModel(application) {
var service: AccountAuthService? = null
private val message = MutableLiveData<String>()
val textRecongnized = MutableLiveData<ArrayList<String>>()
val imagePath = MutableLiveData<Bitmap>()
val locationResult = MutableLiveData<LocationResult>()
fun sendData(msg: String) {
message.value = msg
}
fun getMessage(): LiveData<String> {
return message
}
fun setImage(imagePath: Bitmap) {
this.imagePath.value = imagePath
}
fun setLocationResult(locationResult: LocationResult) {
this.locationResult.value = locationResult
}
fun setTextRecognized(textRecognized: ArrayList<String>) {
this.textRecongnized.value = textRecognized
}
fun logoutHuaweiID() {
if (service != null) {
service!!.signOut()
sendData("KnowMyBoard")
Toast.makeText(getApplication(), "You are logged out from Huawei ID", Toast.LENGTH_LONG)
.show()
}
}
fun loginClicked(view: View?) {
val authParams =
AccountAuthParamsHelper(AccountAuthParams.DEFAULT_AUTH_REQUEST_PARAM).setAuthorizationCode()
.createParams()
service = AccountAuthManager.getService(activity, authParams)
activity!!.startActivityForResult(service?.signInIntent, 8888)
}
fun cancelAuthorization() {
if (service != null) {
// service indicates the AccountAuthService instance generated using the getService method during the sign-in authorization.
service!!.cancelAuthorization().addOnCompleteListener { task ->
if (task.isSuccessful) {
// Processing after a successful authorization cancellation.
Log.i("TAG", "onSuccess: ")
sendData("KnowMyBoard")
Toast.makeText(getApplication(), "Cancelled authorization", Toast.LENGTH_LONG)
.show()
} else {
// Handle the exception.
val exception = task.exception
if (exception is ApiException) {
val statusCode = exception.statusCode
Log.i("TAG", "onFailure: $statusCode")
Toast.makeText(
getApplication(),
"Failed to cancel authorization",
Toast.LENGTH_LONG
).show()
}
}
}
} else {
Toast.makeText(getApplication(), "Login required", Toast.LENGTH_LONG).show()
}
}
fun onClickScan() {
Log.d("TAG", "...Scan...")
}
}
RequestLocationData.kt
Java:
package com.huawei.hms.knowmyboard.dtse.activity.util
import android.Manifest
import androidx.fragment.app.FragmentActivity
import com.huawei.hms.knowmyboard.dtse.activity.viewmodel.LoginViewModel
import android.app.Activity
import android.content.Context
import com.huawei.hmf.tasks.OnSuccessListener
import com.huawei.hms.knowmyboard.dtse.activity.util.RequestLocationData
import com.huawei.hmf.tasks.OnFailureListener
import android.os.Build
import androidx.core.app.ActivityCompat
import android.content.pm.PackageManager
import com.google.gson.Gson
import android.os.Looper
import android.location.Geocoder
import android.util.Log
import com.huawei.hms.location.*
import java.io.IOException
import java.lang.StringBuilder
import java.util.*
class RequestLocationData(
context: Context?,
activity: FragmentActivity?,
loginViewModel: LoginViewModel?
) {
var settingsClient: SettingsClient? = null
private var isLocationSettingSuccess = 0
private var myLocationRequest: LocationRequest? = null
// Define a fusedLocationProviderClient object.
private var fusedLocationProviderClient: FusedLocationProviderClient? = null
var myLocationCallback: LocationCallback? = null
var context: Context? = null
var activity: Activity? = null
var locationResult: LocationResult? = null
var loginViewModel: LoginViewModel? = null
fun initFusionLocationProviderClint() {
// Instantiate the fusedLocationProviderClient object.
fusedLocationProviderClient = LocationServices.getFusedLocationProviderClient(activity)
settingsClient = LocationServices.getSettingsClient(activity)
}
fun checkDeviceLocationSettings() {
val builder = LocationSettingsRequest.Builder()
myLocationRequest = LocationRequest()
builder.addLocationRequest(myLocationRequest)
val locationSettingsRequest = builder.build()
// Check the device location settings.
settingsClient!!.checkLocationSettings(locationSettingsRequest) // Define the listener for success in calling the API for checking device location settings.
.addOnSuccessListener { locationSettingsResponse: LocationSettingsResponse ->
val locationSettingsStates = locationSettingsResponse.locationSettingsStates
val stringBuilder = StringBuilder()
// Check whether the location function is enabled.
stringBuilder.append(",\nisLocationUsable=")
.append(locationSettingsStates.isLocationUsable)
// Check whether HMS Core (APK) is available.
stringBuilder.append(",\nisHMSLocationUsable=")
.append(locationSettingsStates.isHMSLocationUsable)
Log.i(TAG, "checkLocationSetting onComplete:$stringBuilder")
// Set the location type.
myLocationRequest!!.priority = LocationRequest.PRIORITY_HIGH_ACCURACY
// Set the number of location updates to 1.
myLocationRequest!!.numUpdates = 1
isLocationSettingSuccess = 1
} // Define callback for failure in checking the device location settings.
.addOnFailureListener { e -> Log.i(TAG, "checkLocationSetting onFailure:" + e.message) }
}
fun checkPermission() {
// Dynamically apply for required permissions if the API level is 28 or lower.
if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.P) {
Log.i(TAG, "android sdk <= 28 Q")
if (ActivityCompat.checkSelfPermission(
context!!,
Manifest.permission.ACCESS_FINE_LOCATION
) != PackageManager.PERMISSION_GRANTED
&& ActivityCompat.checkSelfPermission(
context!!,
Manifest.permission.ACCESS_COARSE_LOCATION
) != PackageManager.PERMISSION_GRANTED
) {
val strings = arrayOf(
Manifest.permission.READ_EXTERNAL_STORAGE,
Manifest.permission.MANAGE_MEDIA,
Manifest.permission.MEDIA_CONTENT_CONTROL,
Manifest.permission.ACCESS_FINE_LOCATION,
Manifest.permission.ACCESS_COARSE_LOCATION
)
ActivityCompat.requestPermissions(activity!!, strings, 1)
}
} else {
// Dynamically apply for the android.permission.ACCESS_BACKGROUND_LOCATION permission in addition to the preceding permissions if the API level is higher than 28.
if (ActivityCompat.checkSelfPermission(
activity!!,
Manifest.permission.ACCESS_FINE_LOCATION
) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(
context!!,
Manifest.permission.ACCESS_COARSE_LOCATION
) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(
context!!,
"android.permission.ACCESS_BACKGROUND_LOCATION"
) != PackageManager.PERMISSION_GRANTED
) {
val strings = arrayOf(
Manifest.permission.ACCESS_FINE_LOCATION,
Manifest.permission.ACCESS_COARSE_LOCATION,
Manifest.permission.MEDIA_CONTENT_CONTROL,
Manifest.permission.MANAGE_MEDIA,
"android.permission.ACCESS_BACKGROUND_LOCATION"
)
ActivityCompat.requestPermissions(activity!!, strings, 2)
}
}
}
fun refreshLocation(): LocationResult? {
Log.d(TAG, "Refreshing location")
if (isLocationSettingSuccess == 1) {
myLocationCallback = object : LocationCallback() {
override fun onLocationResult(locationResult: LocationResult) {
if (locationResult != null) {
val gson = Gson()
Log.d(
TAG,
" Location data :" + locationResult.lastLocation.latitude + " : " + locationResult.lastLocation.longitude
)
Log.d(TAG, " Location data :" + gson.toJson(locationResult.lastHWLocation))
Log.d(TAG, " Location data :" + locationResult.lastHWLocation.countryName)
Log.d(TAG, " Location data :" + locationResult.lastHWLocation.latitude)
Log.d(TAG, " Location data :" + locationResult.lastHWLocation.longitude)
// binding.textDetected.setText("Latitude " + locationResult.getLastHWLocation().getLatitude() + " Longitude " + locationResult.getLastHWLocation().getLongitude());
getGeoCoderValues(
locationResult.lastHWLocation.latitude,
locationResult.lastHWLocation.longitude
)
//locationResult = locationResult1;
loginViewModel!!.setLocationResult(locationResult)
}
}
}
fusedLocationProviderClient!!.requestLocationUpdates(
myLocationRequest,
myLocationCallback,
Looper.getMainLooper()
)
} else {
Log.d(TAG, "Failed to get location settings")
}
return locationResult
}
fun disableLocationData() {
fusedLocationProviderClient!!.disableBackgroundLocation()
fusedLocationProviderClient!!.removeLocationUpdates(myLocationCallback)
}
private fun getGeoCoderValues(latitude: Double, longitude: Double) {
getAddress(context, latitude, longitude)
/* Geocoder geocoder;
List<Address> addresses;
Locale locale = new Locale("en", "IN");
geocoder = new Geocoder(getContext(), locale);
try {
addresses = geocoder.getFromLocation(latitude, longitude, 1); // Here 1 represent max location result to returned, by documents it recommended 1 to 5
Gson gson=new Gson();
Log.d(TAG,"Geo coder :"+gson.toJson(addresses));
String address = addresses.get(0).getAddressLine(0); // If any additional address line present than only, check with max available address lines by getMaxAddressLineIndex()
String city = addresses.get(0).getLocality();
String state = addresses.get(0).getAdminArea();
String country = addresses.get(0).getCountryName();
String postalCode = addresses.get(0).getPostalCode();
String knownName = addresses.get(0).getFeatureName();
} catch (IOException e) {
e.printStackTrace();
Log.e(TAG,"Error while fetching Geo coder :"+e.getMessage());
}*/
/* Locale locale = new Locale("en", "IN");
GeocoderService geocoderService =
LocationServices.getGeocoderService(getActivity().getBaseContext(), locale);
// Request reverse geocoding.
GetFromLocationRequest getFromLocationRequest = new GetFromLocationRequest(latitude, longitude, 5);
// Initiate reverse geocoding.
geocoderService.getFromLocation(getFromLocationRequest)
.addOnSuccessListener(hwLocation -> {
Gson gson=new Gson();
Log.d(TAG,"Geo coder :"+gson.toJson(hwLocation));
})
.addOnFailureListener(e -> {
Log.e(TAG,"Error while fetching Geo coder :"+e.getMessage());
});*/
}
companion object {
var TAG = "TAG"
fun getAddress(context: Context?, LATITUDE: Double, LONGITUDE: Double) {
//Set Address
try {
val geocoder = Geocoder(context, Locale.getDefault())
val addresses = geocoder.getFromLocation(LATITUDE, LONGITUDE, 1)
if (addresses != null && addresses.size > 0) {
val address =
addresses[0].getAddressLine(0) // If any additional address line present than only, check with max available address lines by getMaxAddressLineIndex()
val city = addresses[0].locality
val state = addresses[0].adminArea
val country = addresses[0].countryName
val postalCode = addresses[0].postalCode
val knownName = addresses[0].featureName // Only if available else return NULL
Log.d(TAG, "getAddress: address$address")
Log.d(TAG, "getAddress: city$city")
Log.d(TAG, "getAddress: state$state")
Log.d(TAG, "getAddress: postalCode$postalCode")
Log.d(TAG, "getAddress: knownName$knownName")
}
} catch (e: IOException) {
e.printStackTrace()
Log.e(TAG, "Error while fetching Geo coder :" + e.message)
}
}
}
init {
this.context = context
this.activity = activity
[email protected] = loginViewModel
}
}
LoginFragment.kt
Java:
package com.huawei.hms.knowmyboard.dtse.activity.fragments
import com.huawei.hms.knowmyboard.dtse.activity.viewmodel.LoginViewModel
import androidx.navigation.Navigation.findNavController
import android.content.SharedPreferences
import androidx.navigation.NavController
import android.os.Bundle
import androidx.databinding.DataBindingUtil
import androidx.lifecycle.ViewModelProvider
import android.annotation.SuppressLint
import android.content.Context
import android.util.Log
import android.view.*
import androidx.fragment.app.Fragment
import com.huawei.hms.knowmyboard.dtse.R
import java.lang.Exception
class LoginFragment : Fragment() {
var loginBinding: FragmentLoginBinding? = null
var loginViewModel: LoginViewModel? = null
var menu: Menu? = null
var prefs: SharedPreferences? = null
var editor: SharedPreferences.Editor? = null
var navController: NavController? = null
private val MY_PREF_NAME = "my_pref_name"
private val TAG = "TAG"
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
navController = findNavController(view)
}
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
loginBinding = DataBindingUtil.inflate(inflater, R.layout.fragment_login, container, false)
loginViewModel = ViewModelProvider(requireActivity()).get(LoginViewModel::class.java)
loginBinding?.loginViewModel = loginViewModel
Log.d(TAG, " Pref $preferenceValue")
if (preferenceValue == "user_name") {
loginBinding?.btnHuaweiIdAuth?.visibility = View.VISIBLE
} else {
enableMenu(menu)
requireActivity().title = preferenceValue
loginBinding?.btnHuaweiIdAuth?.visibility = View.GONE
}
loginBinding?.imageLogo?.setOnClickListener { v: View? -> navController!!.navigate(R.id.action_loginFragment_to_mainFragment) }
loginViewModel!!.getMessage().observeForever { message ->
updateMessage(message)
if (message != resources.getString(R.string.app_name)) {
preferenceValue = message
enableMenu(menu)
loginBinding?.btnHuaweiIdAuth?.visibility = View.GONE
} else {
disableMenu(menu)
loginBinding?.btnHuaweiIdAuth?.visibility = View.VISIBLE
preferenceValue = "user_name"
}
}
return loginBinding?.root
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setHasOptionsMenu(true)
}
override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) {
menu.clear()
super.onCreateOptionsMenu(menu, inflater)
inflater.inflate(R.menu.main, menu)
this.menu = menu
disableMenu(menu)
}
private fun disableMenu(menu: Menu?) {
try {
if (menu != null) {
if (preferenceValue == "user_name") {
menu.findItem(R.id.menu_login_logout).isVisible = false
menu.findItem(R.id.menu_cancel_auth).isVisible = false
requireActivity().title = resources.getString(R.string.app_name)
} else {
menu.findItem(R.id.menu_login_logout).isVisible = true
menu.findItem(R.id.menu_cancel_auth).isVisible = true
}
}
} catch (e: Exception) {
e.printStackTrace()
}
}
private fun enableMenu(menu: Menu?) {
try {
menu!!.findItem(R.id.menu_login_logout).isVisible = true
menu.findItem(R.id.menu_cancel_auth).isVisible = true
} catch (e: Exception) {
e.printStackTrace()
}
}
@SuppressLint("NonConstantResourceId")
override fun onOptionsItemSelected(item: MenuItem): Boolean {
when (item.itemId) {
R.id.menu_cancel_auth -> {
preferenceValue = "user_name"
loginViewModel!!.cancelAuthorization()
loginBinding!!.btnHuaweiIdAuth.visibility = View.VISIBLE
disableMenu(menu)
return true
}
R.id.menu_login_logout -> {
preferenceValue = "user_name"
loginViewModel!!.logoutHuaweiID()
loginBinding!!.btnHuaweiIdAuth.visibility = View.VISIBLE
disableMenu(menu)
return true
}
else -> {}
}
return super.onOptionsItemSelected(item)
}
private fun updateMessage(msg: String?) {
//loginBinding.txtMessage.setText(msg);
requireActivity().title = msg
}
var preferenceValue: String?
get() {
prefs = requireActivity().getSharedPreferences(MY_PREF_NAME, Context.MODE_PRIVATE)
return prefs?.getString("user_name", "user_name")
}
set(userName) {
editor = requireActivity().getSharedPreferences(MY_PREF_NAME, Context.MODE_PRIVATE).edit()
editor?.putString("user_name", userName)
editor?.apply()
}
}
MainFragment.kt
Java:
package com.huawei.hms.knowmyboard.dtse.activity.fragments
import com.huawei.hms.knowmyboard.dtse.activity.viewmodel.LoginViewModel
import com.huawei.hms.knowmyboard.dtse.activity.util.RequestLocationData
import android.os.Bundle
import androidx.databinding.DataBindingUtil
import androidx.lifecycle.ViewModelProvider
import android.content.Intent
import android.annotation.SuppressLint
import android.util.Log
import android.view.*
import androidx.fragment.app.Fragment
import com.huawei.hms.knowmyboard.dtse.R
import com.huawei.hms.knowmyboard.dtse.databinding.FragmentMainFragmentBinding
import java.lang.Exception
class MainFragment : Fragment() {
var binding: FragmentMainFragmentBinding? = null
var loginViewModel: LoginViewModel? = null
var locationData: RequestLocationData? = null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setHasOptionsMenu(true)
}
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
// Inflate the layout for this fragment
binding =
DataBindingUtil.inflate(inflater, R.layout.fragment_main_fragment, container, false)
// settingsClient = LocationServices.getSettingsClient(getActivity());
loginViewModel = ViewModelProvider(requireActivity()).get(LoginViewModel::class.java)
binding?.loginViewModel = loginViewModel
locationData = RequestLocationData(context, activity, loginViewModel)
locationData!!.initFusionLocationProviderClint()
locationData!!.checkPermission()
locationData!!.checkDeviceLocationSettings()
// checkDeviceLocationSettings();
// Instantiate the fusedLocationProviderClient object.
// fusedLocationProviderClient = LocationServices.getFusedLocationProviderClient(getActivity());
binding?.buttonScan?.setOnClickListener {
Log.d(TAG, "*******")
//loginViewModel.setTextRecongnized("");
scan()
}
loginViewModel!!.imagePath.observeForever { bitmap ->
try {
binding?.imageView?.setImageBitmap(bitmap)
} catch (e: Exception) {
e.printStackTrace()
Log.e("TAG", "Error : " + e.message)
}
}
loginViewModel!!.textRecongnized.observeForever { res ->
Log.i("TAG", "OBSERVER : " + "Language : " + getStringResourceByName(
res[0].trim { it <= ' ' }) +
" Detected text : " + res[1].trim { it <= ' ' } +
" Translated text : " + res[2].trim { it <= ' ' })
binding?.textLanguage?.text = "Language : " + getStringResourceByName(res[0])
binding?.textDetected?.text = "Detected text : " + res[1]
binding?.textTranslated?.text = "Translated text : " + res[2]
}
loginViewModel!!.locationResult.observeForever { locationResult ->
binding?.textDetected?.text =
"Latitude " + locationResult.lastHWLocation.latitude + " Longitude " + locationResult.lastHWLocation.longitude
}
return binding?.root
}
private fun getStringResourceByName(aString: String): String {
val packageName = requireActivity().packageName
val resId = resources
.getIdentifier(aString, "string", packageName)
return if (resId == 0) {
aString
} else {
getString(resId)
}
}
private fun scan() {
/* MLTextAnalyzer analyzer = new MLTextAnalyzer.Factory(getContext()).create();
analyzer.setTransactor(new OcrDetectorProcessor());
LensEngine lensEngine = new LensEngine.Creator(getContext(), analyzer)
.setLensType(LensEngine.BACK_LENS)
.applyDisplayDimension(1440, 1080)
.applyFps(30.0f)
.enableAutomaticFocus(true)
.create();
SurfaceView mSurfaceView = new SurfaceView(getContext());
try {
lensEngine.run(mSurfaceView.getHolder());
} catch (IOException e) {
// Exception handling logic.
Log.e(TAG,e.getMessage());
}*/
val intent = Intent(Intent.ACTION_GET_CONTENT)
intent.type = "image/*"
requireActivity().startActivityForResult(intent, 2323)
}
override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) {
menu.clear()
super.onCreateOptionsMenu(menu, inflater)
inflater.inflate(R.menu.main_fragment_menu, menu)
}
@SuppressLint("NonConstantResourceId")
override fun onOptionsItemSelected(item: MenuItem): Boolean {
when (item.itemId) {
R.id.option_refresh_location -> {
//refreshLocation();
locationData!!.refreshLocation()
return true
}
}
return super.onOptionsItemSelected(item)
}
/* private void checkDeviceLocationSettings() {
LocationSettingsRequest.Builder builder = new LocationSettingsRequest.Builder();
myLocationRequest = new LocationRequest();
builder.addLocationRequest(myLocationRequest);
LocationSettingsRequest locationSettingsRequest = builder.build();
// Check the device location settings.
settingsClient.checkLocationSettings(locationSettingsRequest)
// Define the listener for success in calling the API for checking device location settings.
.addOnSuccessListener(locationSettingsResponse -> {
LocationSettingsStates locationSettingsStates =
locationSettingsResponse.getLocationSettingsStates();
StringBuilder stringBuilder = new StringBuilder();
// Check whether the location function is enabled.
stringBuilder.append(",\nisLocationUsable=")
.append(locationSettingsStates.isLocationUsable());
// Check whether HMS Core (APK) is available.
stringBuilder.append(",\nisHMSLocationUsable=")
.append(locationSettingsStates.isHMSLocationUsable());
Log.i(TAG, "checkLocationSetting onComplete:" + stringBuilder.toString());
// Set the location type.
myLocationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
// Set the number of location updates to 1.
myLocationRequest.setNumUpdates(1);
isLocationSettingSuccess = 1;
})
// Define callback for failure in checking the device location settings.
.addOnFailureListener(new OnFailureListener() {
@Override
public void onFailure(Exception e) {
isLocationSettingSuccess = 0;
Log.i(TAG, "checkLocationSetting onFailure:" + e.getMessage());
}
});
}*/
/* private void refreshLocation() {
Log.d(TAG, "Refreshing location");
if (isLocationSettingSuccess == 1) {
myLocationCallback = new LocationCallback() {
@Override
public void onLocationResult(LocationResult locationResult) {
if (locationResult != null) {
Gson gson = new Gson();
Log.d(TAG, " Location data :" + locationResult.getLastLocation().getLatitude() + " : " + locationResult.getLastLocation().getLongitude());
Log.d(TAG, " Location data :" + gson.toJson(locationResult.getLastHWLocation()));
Log.d(TAG, " Location data :" + locationResult.getLastHWLocation().getCountryName());
Log.d(TAG, " Location data :" + locationResult.getLastHWLocation().getLatitude());
Log.d(TAG, " Location data :" + locationResult.getLastHWLocation().getLongitude());
binding.textDetected.setText("Latitude " + locationResult.getLastHWLocation().getLatitude() + " Longitude " + locationResult.getLastHWLocation().getLongitude());
getGeoCoderValues(locationResult.getLastHWLocation().getLatitude(),locationResult.getLastHWLocation().getLongitude());
}
}
};
fusedLocationProviderClient.requestLocationUpdates(myLocationRequest, myLocationCallback, Looper.getMainLooper());
} else {
Log.d(TAG, "Failed to get location settings");
}
}*/
/*private void getGeoCoderValues(double latitude, double longitude) {
Locale locale = new Locale("en", "in");
GeocoderService geocoderService =
LocationServices.getGeocoderService(getActivity().getBaseContext(), locale);
// Request reverse geocoding.
GetFromLocationRequest getFromLocationRequest = new GetFromLocationRequest(latitude, longitude, 5);
// Initiate reverse geocoding.
geocoderService.getFromLocation(getFromLocationRequest)
.addOnSuccessListener(hwLocation -> {
Gson gson=new Gson();
Log.d(TAG,"Geo coder :"+gson.toJson(hwLocation));
})
.addOnFailureListener(e -> {
// TODO: Processing when the API call fails.
Log.e(TAG,"Error while fetching Geo coder :"+e.getMessage());
});
}*/
/* void checkPermission() {
// Dynamically apply for required permissions if the API level is 28 or lower.
if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.P) {
Log.i(TAG, "android sdk <= 28 Q");
if (ActivityCompat.checkSelfPermission(getContext(),
Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED
&& ActivityCompat.checkSelfPermission(getContext(),
Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
String[] strings =
{Manifest.permission.READ_EXTERNAL_STORAGE,Manifest.permission.MANAGE_MEDIA,Manifest.permission.MEDIA_CONTENT_CONTROL,Manifest.permission.ACCESS_FINE_LOCATION, Manifest.permission.ACCESS_COARSE_LOCATION};
ActivityCompat.requestPermissions(getActivity(), strings, 1);
}
} else {
// Dynamically apply for the android.permission.ACCESS_BACKGROUND_LOCATION permission in addition to the preceding permissions if the API level is higher than 28.
if (ActivityCompat.checkSelfPermission(getActivity(),
Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED
&& ActivityCompat.checkSelfPermission(getContext(),
Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED
&& ActivityCompat.checkSelfPermission(getContext(),
"android.permission.ACCESS_BACKGROUND_LOCATION") != PackageManager.PERMISSION_GRANTED) {
String[] strings = {android.Manifest.permission.ACCESS_FINE_LOCATION,
android.Manifest.permission.ACCESS_COARSE_LOCATION,Manifest.permission.MEDIA_CONTENT_CONTROL,Manifest.permission.MANAGE_MEDIA,
"android.permission.ACCESS_BACKGROUND_LOCATION"};
ActivityCompat.requestPermissions(getActivity(), strings, 2);
}
}
}*/
override fun onStop() {
super.onStop()
locationData!!.disableLocationData()
}
companion object {
var TAG = "TAG"
}
}
Result
Tricks and Tips
Makes sure that agconnect-services.json file added.
Make sure required dependencies are added
Make sure that ML service is enabled in AGC
Images has clear visibility of text
ConclusionIn this article, we have learnt how to integrate the Huawei Location kit and ML kit into the Android application KnowMyBoard. And also we have learnt how to convert the image to text Using HMS ML service, In my previous article I have written an article about account kit please go through the previous article which is available in the introduction section. barrier.
Reference
ML Kit – Training video
Location Kit – Training video
IntroductionIn this article, we will learn how to integrate Huawei ML kit, Map kit and Location kit in Android application KnowMyBoard. Account Kit provides seamless login functionality to the app with large user base.
Location kit SDK for Android offers location-related APIs for Android apps. These APIs mainly relate to 6 functions like fused location, activity identification, geofence, high-precision location, indoor location, and geocoding. This mode is applicable to mobile phones and Huawei tablets. We are using Location kit to get location of user.
Huawei Map SDK for Android is a set of APIs that can be called to develop maps. You can use this SDK to easily add map-related functions to your Android app, including map display, map interaction, map drawing, and map style customization.
Supported Countries/Regions
Supported Countries/Regions
Development Overview
You need to install Android Studio IDE and I assume that you have prior knowledge of Android application development.
Hardware Requirements
A computer (desktop or laptop) running Windows 10.
Android phone (with the USB cable), which is used for debugging.
Software Requirements
Java JDK 1.8 or later.
Android Studio software or Visual Studio or Code installed.
HMS Core (APK) 4.X or later
Integration steps
Step 1. Huawei developer account and complete identity verification in Huawei developer website, refer to register Huawei ID.
Step 2. Create project in AppGallery Connect
Step 3. Adding HMS Core SDK
Let's start coding
MainActivity.kt
Java:
package com.huawei.hms.knowmyboard.dtse.activity.view
import androidx.navigation.Navigation.findNavController
import androidx.navigation.ui.NavigationUI.setupWithNavController
import com.huawei.hms.knowmyboard.dtse.activity.viewmodel.LoginViewModel
import android.graphics.Bitmap
import com.huawei.hms.mlsdk.langdetect.local.MLLocalLangDetector
import com.huawei.hms.mlsdk.translate.local.MLLocalTranslator
import android.app.ProgressDialog
import androidx.navigation.NavController
import android.os.Bundle
import androidx.databinding.DataBindingUtil
import com.huawei.hms.knowmyboard.dtse.activity.app.MyApplication
import android.content.Intent
import com.huawei.hms.support.account.AccountAuthManager
import android.provider.MediaStore
import com.huawei.hmf.tasks.OnSuccessListener
import com.huawei.hms.mlsdk.langdetect.MLLangDetectorFactory
import com.huawei.hms.mlsdk.langdetect.local.MLLocalLangDetectorSetting
import com.huawei.hmf.tasks.OnFailureListener
import android.content.DialogInterface
import android.net.Uri
import android.util.Log
import androidx.appcompat.app.AlertDialog
import androidx.appcompat.app.AppCompatActivity
import androidx.lifecycle.ViewModelProvider
import com.google.android.material.bottomnavigation.BottomNavigationView
import com.huawei.hms.common.ApiException
import com.huawei.hms.knowmyboard.dtse.R
import com.huawei.hms.knowmyboard.dtse.activity.model.UserData
import com.huawei.hms.knowmyboard.dtse.activity.util.Constants
import com.huawei.hms.knowmyboard.dtse.databinding.ActivityMainBinding
import com.huawei.hms.mlsdk.MLAnalyzerFactory
import com.huawei.hms.mlsdk.common.MLApplication
import com.huawei.hms.mlsdk.common.MLFrame
import com.huawei.hms.mlsdk.translate.local.MLLocalTranslateSetting
import com.huawei.hms.mlsdk.translate.MLTranslatorFactory
import com.huawei.hms.mlsdk.model.download.MLModelDownloadStrategy
import com.huawei.hms.mlsdk.model.download.MLModelDownloadListener
import com.huawei.hms.mlsdk.text.MLLocalTextSetting
import com.huawei.hms.mlsdk.text.MLText
import com.huawei.hms.mlsdk.text.MLTextAnalyzer
import java.io.IOException
import java.lang.Exception
import java.util.ArrayList
class MainActivity() : AppCompatActivity() {
var loginViewModel: LoginViewModel? = null
private var mTextAnalyzer: MLTextAnalyzer? = null
var imagePath: Uri? = null
var bitmap: Bitmap? = null
var result = ArrayList<String>()
var myLocalLangDetector: MLLocalLangDetector? = null
var myLocalTranslator: MLLocalTranslator? = null
var textRecognized: String? = null
var progressDialog: ProgressDialog? = null
var navController: NavController? = null
var activityMainBinding: ActivityMainBinding? = null
var bottomNavigationView: BottomNavigationView? = null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
activityMainBinding =
DataBindingUtil.setContentView([email protected], R.layout.activity_main)
loginViewModel = ViewModelProvider([email protected]).get(
LoginViewModel::class.java
)
navController = findNavController([email protected], R.id.nav_host_fragment)
MyApplication.activity = this
progressDialog = ProgressDialog(this)
progressDialog!!.setCancelable(false)
bottomNavigationView = activityMainBinding!!.bottomNavigation
setupWithNavController(bottomNavigationView!!, navController!!)
}
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
// Process the authorization result to obtain the authorization code from AuthAccount.
super.onActivityResult(requestCode, resultCode, data)
if (requestCode == 1234) {
Log.e("TAG", " Result can be pulled")
}
if (requestCode == 8888) {
val authAccountTask = AccountAuthManager.parseAuthResultFromIntent(data)
if (authAccountTask.isSuccessful) {
// The sign-in is successful, and the user's ID information and authorization code are obtained.
val authAccount = authAccountTask.result
val userData = UserData()
userData.accessToken = authAccount.accessToken
userData.countryCode = authAccount.countryCode
userData.displayName = authAccount.displayName
userData.email = authAccount.email
userData.familyName = authAccount.familyName
userData.givenName = authAccount.givenName
userData.idToken = authAccount.idToken
userData.openId = authAccount.openId
userData.uid = authAccount.uid
userData.photoUriString = authAccount.avatarUri.toString()
userData.unionId = authAccount.unionId
loginViewModel = ViewModelProvider([email protected]).get(
LoginViewModel::class.java
)
loginViewModel!!.sendData(authAccount.displayName)
} else {
// The sign-in failed.
Log.e(
"TAG",
"sign in failed:" + (authAccountTask.exception as ApiException).statusCode
)
}
}
if ((requestCode == 2323) && (resultCode == RESULT_OK) && (data != null)) {
progressDialog!!.setMessage("Initializing text detection..")
progressDialog!!.show()
imagePath = data.data
try {
bitmap = MediaStore.Images.Media.getBitmap(this.contentResolver, imagePath)
asyncAnalyzeText(bitmap)
} catch (e: IOException) {
e.printStackTrace()
Log.e("TAG", " BITMAP ERROR")
}
}
if ((requestCode == 2424) && (resultCode == RESULT_OK) && (data != null)) {
progressDialog!!.setMessage("Initializing text detection..")
progressDialog!!.show()
try {
bitmap = data.extras!!["data"] as Bitmap?
asyncAnalyzeText(bitmap)
} catch (e: Exception) {
e.printStackTrace()
Log.e("TAG", " BITMAP ERROR")
}
}
}
private fun asyncAnalyzeText(bitmap: Bitmap?) {
if (mTextAnalyzer == null) {
createMLTextAnalyzer()
}
val frame = MLFrame.fromBitmap(bitmap)
val task = mTextAnalyzer!!.asyncAnalyseFrame(frame)
task.addOnSuccessListener(object : OnSuccessListener<MLText> {
override fun onSuccess(text: MLText) {
progressDialog!!.setMessage("Initializing language detection..")
textRecognized = text.stringValue.trim { it <= ' ' }
if (!textRecognized!!.isEmpty()) {
// Create a local language detector.
val factory = MLLangDetectorFactory.getInstance()
val setting =
MLLocalLangDetectorSetting.Factory() // Set the minimum confidence threshold for language detection.
.setTrustedThreshold(0.01f)
.create()
myLocalLangDetector = factory.getLocalLangDetector(setting)
val firstBestDetectTask = myLocalLangDetector!!.firstBestDetect(textRecognized)
firstBestDetectTask.addOnSuccessListener(OnSuccessListener { languageDetected ->
progressDialog!!.setMessage("Initializing text translation..")
// Processing logic for detection success.
textTranslate(languageDetected, textRecognized!!, bitmap)
}).addOnFailureListener(object : OnFailureListener {
override fun onFailure(e: Exception) {
// Processing logic for detection failure.
Log.e("TAG", "Lang detect error:" + e.message)
}
})
} else {
progressDialog!!.dismiss()
showErrorDialog("Failed to recognize text.")
}
}
}).addOnFailureListener(object : OnFailureListener {
override fun onFailure(e: Exception) {
Log.e("TAG", "#==>" + e.message)
}
})
}
private fun showErrorDialog(msg: String) {
val alertDialog = AlertDialog.Builder(this).create()
alertDialog.setTitle("Error")
alertDialog.setMessage(msg)
alertDialog.setButton(
AlertDialog.BUTTON_POSITIVE,
"OK",
object : DialogInterface.OnClickListener {
override fun onClick(dialog: DialogInterface, which: Int) {
dialog.dismiss()
}
})
alertDialog.show()
}
private fun textTranslate(languageDetected: String, textRecognized: String, uri: Bitmap?) {
MLApplication.initialize(application)
MLApplication.getInstance().apiKey = Constants.API_KEY
// Create an offline translator.
val setting =
MLLocalTranslateSetting.Factory() // Set the source language code. The ISO 639-1 standard is used. This parameter is mandatory. If this parameter is not set, an error may occur.
.setSourceLangCode(languageDetected) // Set the target language code. The ISO 639-1 standard is used. This parameter is mandatory. If this parameter is not set, an error may occur.
.setTargetLangCode("en")
.create()
myLocalTranslator = MLTranslatorFactory.getInstance().getLocalTranslator(setting)
// Set the model download policy.
val downloadStrategy = MLModelDownloadStrategy.Factory()
.needWifi() // It is recommended that you download the package in a Wi-Fi environment.
.create()
// Create a download progress listener.
val modelDownloadListener: MLModelDownloadListener = object : MLModelDownloadListener {
override fun onProcess(alreadyDownLength: Long, totalLength: Long) {
runOnUiThread(object : Runnable {
override fun run() {
// Display the download progress or perform other operations.
}
})
}
}
myLocalTranslator!!.preparedModel(downloadStrategy, modelDownloadListener)
.addOnSuccessListener(object : OnSuccessListener<Void?> {
override fun onSuccess(aVoid: Void?) {
// Called when the model package is successfully downloaded.
// input is a string of less than 5000 characters.
val task = myLocalTranslator!!.asyncTranslate(textRecognized)
// Before translation, ensure that the models have been successfully downloaded.
task.addOnSuccessListener(object : OnSuccessListener<String> {
override fun onSuccess(translated: String) {
// Processing logic for detection success.
result.clear()
result.add(languageDetected.trim { it <= ' ' })
result.add(textRecognized.trim { it <= ' ' })
result.add(translated.trim { it <= ' ' })
loginViewModel!!.setImage(uri!!)
loginViewModel!!.setTextRecongnized(result)
progressDialog!!.dismiss()
}
}).addOnFailureListener(object : OnFailureListener {
override fun onFailure(e: Exception) {
// Processing logic for detection failure.
progressDialog!!.dismiss()
}
})
}
}).addOnFailureListener(object : OnFailureListener {
override fun onFailure(e: Exception) {
// Called when the model package fails to be downloaded.
progressDialog!!.dismiss()
}
})
}
private fun createMLTextAnalyzer() {
val setting = MLLocalTextSetting.Factory()
.setOCRMode(MLLocalTextSetting.OCR_DETECT_MODE)
.create()
mTextAnalyzer = MLAnalyzerFactory.getInstance().getLocalTextAnalyzer(setting)
}
override fun onStop() {
if (myLocalLangDetector != null) {
myLocalLangDetector!!.stop()
}
if (myLocalTranslator != null) {
myLocalTranslator!!.stop()
}
if (progressDialog != null) {
progressDialog!!.dismiss()
}
super.onStop()
}
companion object {
var TAG = "TAG"
}
}
Result
{
"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"
}
Tricks and Tips
Makes sure that agconnect-services.json file added.
Make sure required dependencies are added
Make sure that service is enabled in AGC
Enable data binding in gradle.build file
Make sure bottom navigation id's should be same as fragment id's in navigation graph
Conclusion
In this article, we have learnt how to integrate Huawei Map kit, Location kit in Android application KnowMyBoard. Hoping that the Map kit capabilities are helpful to you as well, like this sample, you can make use of Map kit as per your requirement.
Thank you so much for reading. I hope this article helps you to understand the integration of Huawei Map kit and Location kit in Android application KnowMyBoard.
Reference
Map Kit – Training video
Location Kit – Training video
Introduction
Site Kit is basically used for apps to provide the place related services. This kit provide to search the places with keyword, Find nearby place, place suggestion for user input, Get place details using the unique id.
Features of Huawei Site Kit
Keyword search: Returns a place list based on keywords entered by the user.
Nearby place search: Searches for nearby places based on the current location of the user's device.
Place details: Searches for details about a place.
Search suggestion: Returns a list of place suggestions.
Site Search: Returns a site object.
Development Overview
You need to install Android Studio IDE and I assume that you have prior knowledge of Android application development.
Hardware Requirements
A computer (desktop or laptop) running Windows 10.
Android phone (with the USB cable), which is used for debugging.
Software Requirements
Java JDK 1.8 or later.
Android Studio software or Visual Studio or Code installed.
HMS Core (APK) 4.X or later
Integration steps
Step 1. Huawei developer account and complete identity verification in Huawei developer website, refer to register Huawei ID.
Step 2. Create project in AppGallery Connect
Step 3. Adding HMS Core SDK
Let's start coding
MainActivity.kt
Java:
package com.huawei.hms.knowmyboard.dtse.activity.view
import androidx.navigation.Navigation.findNavController
import androidx.navigation.ui.NavigationUI.setupWithNavController
import com.huawei.hms.knowmyboard.dtse.activity.viewmodel.LoginViewModel
import android.graphics.Bitmap
import com.huawei.hms.mlsdk.langdetect.local.MLLocalLangDetector
import com.huawei.hms.mlsdk.translate.local.MLLocalTranslator
import android.app.ProgressDialog
import androidx.navigation.NavController
import android.os.Bundle
import androidx.databinding.DataBindingUtil
import com.huawei.hms.knowmyboard.dtse.activity.app.MyApplication
import android.content.Intent
import com.huawei.hms.support.account.AccountAuthManager
import android.provider.MediaStore
import com.huawei.hmf.tasks.OnSuccessListener
import com.huawei.hms.mlsdk.langdetect.MLLangDetectorFactory
import com.huawei.hms.mlsdk.langdetect.local.MLLocalLangDetectorSetting
import com.huawei.hmf.tasks.OnFailureListener
import android.content.DialogInterface
import android.net.Uri
import android.util.Log
import androidx.appcompat.app.AlertDialog
import androidx.appcompat.app.AppCompatActivity
import androidx.lifecycle.ViewModelProvider
import com.google.android.material.bottomnavigation.BottomNavigationView
import com.huawei.hms.common.ApiException
import com.huawei.hms.knowmyboard.dtse.R
import com.huawei.hms.knowmyboard.dtse.activity.model.UserData
import com.huawei.hms.knowmyboard.dtse.activity.util.Constants
import com.huawei.hms.knowmyboard.dtse.databinding.ActivityMainBinding
import com.huawei.hms.mlsdk.MLAnalyzerFactory
import com.huawei.hms.mlsdk.common.MLApplication
import com.huawei.hms.mlsdk.common.MLFrame
import com.huawei.hms.mlsdk.translate.local.MLLocalTranslateSetting
import com.huawei.hms.mlsdk.translate.MLTranslatorFactory
import com.huawei.hms.mlsdk.model.download.MLModelDownloadStrategy
import com.huawei.hms.mlsdk.model.download.MLModelDownloadListener
import com.huawei.hms.mlsdk.text.MLLocalTextSetting
import com.huawei.hms.mlsdk.text.MLText
import com.huawei.hms.mlsdk.text.MLTextAnalyzer
import java.io.IOException
import java.lang.Exception
import java.util.ArrayList
class MainActivity() : AppCompatActivity() {
var loginViewModel: LoginViewModel? = null
private var mTextAnalyzer: MLTextAnalyzer? = null
var imagePath: Uri? = null
var bitmap: Bitmap? = null
var result = ArrayList<String>()
var myLocalLangDetector: MLLocalLangDetector? = null
var myLocalTranslator: MLLocalTranslator? = null
var textRecognized: String? = null
var progressDialog: ProgressDialog? = null
var navController: NavController? = null
var activityMainBinding: ActivityMainBinding? = null
var bottomNavigationView: BottomNavigationView? = null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
activityMainBinding =
DataBindingUtil.setContentView([email protected], R.layout.activity_main)
loginViewModel = ViewModelProvider([email protected]).get(
LoginViewModel::class.java
)
navController = findNavController([email protected], R.id.nav_host_fragment)
MyApplication.activity = this
progressDialog = ProgressDialog(this)
progressDialog!!.setCancelable(false)
bottomNavigationView = activityMainBinding!!.bottomNavigation
setupWithNavController(bottomNavigationView!!, navController!!)
}
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
// Process the authorization result to obtain the authorization code from AuthAccount.
super.onActivityResult(requestCode, resultCode, data)
if (requestCode == 1234) {
Log.e("TAG", " Result can be pulled")
}
if (requestCode == 8888) {
val authAccountTask = AccountAuthManager.parseAuthResultFromIntent(data)
if (authAccountTask.isSuccessful) {
// The sign-in is successful, and the user's ID information and authorization code are obtained.
val authAccount = authAccountTask.result
val userData = UserData()
userData.accessToken = authAccount.accessToken
userData.countryCode = authAccount.countryCode
userData.displayName = authAccount.displayName
userData.email = authAccount.email
userData.familyName = authAccount.familyName
userData.givenName = authAccount.givenName
userData.idToken = authAccount.idToken
userData.openId = authAccount.openId
userData.uid = authAccount.uid
userData.photoUriString = authAccount.avatarUri.toString()
userData.unionId = authAccount.unionId
loginViewModel = ViewModelProvider([email protected]).get(
LoginViewModel::class.java
)
loginViewModel!!.sendData(authAccount.displayName)
} else {
// The sign-in failed.
Log.e(
"TAG",
"sign in failed:" + (authAccountTask.exception as ApiException).statusCode
)
}
}
if ((requestCode == 2323) && (resultCode == RESULT_OK) && (data != null)) {
progressDialog!!.setMessage("Initializing text detection..")
progressDialog!!.show()
imagePath = data.data
try {
bitmap = MediaStore.Images.Media.getBitmap(this.contentResolver, imagePath)
asyncAnalyzeText(bitmap)
} catch (e: IOException) {
e.printStackTrace()
Log.e("TAG", " BITMAP ERROR")
}
}
if ((requestCode == 2424) && (resultCode == RESULT_OK) && (data != null)) {
progressDialog!!.setMessage("Initializing text detection..")
progressDialog!!.show()
try {
bitmap = data.extras!!["data"] as Bitmap?
asyncAnalyzeText(bitmap)
} catch (e: Exception) {
e.printStackTrace()
Log.e("TAG", " BITMAP ERROR")
}
}
}
private fun asyncAnalyzeText(bitmap: Bitmap?) {
if (mTextAnalyzer == null) {
createMLTextAnalyzer()
}
val frame = MLFrame.fromBitmap(bitmap)
val task = mTextAnalyzer!!.asyncAnalyseFrame(frame)
task.addOnSuccessListener(object : OnSuccessListener<MLText> {
override fun onSuccess(text: MLText) {
progressDialog!!.setMessage("Initializing language detection..")
textRecognized = text.stringValue.trim { it <= ' ' }
if (!textRecognized!!.isEmpty()) {
// Create a local language detector.
val factory = MLLangDetectorFactory.getInstance()
val setting =
MLLocalLangDetectorSetting.Factory() // Set the minimum confidence threshold for language detection.
.setTrustedThreshold(0.01f)
.create()
myLocalLangDetector = factory.getLocalLangDetector(setting)
val firstBestDetectTask = myLocalLangDetector!!.firstBestDetect(textRecognized)
firstBestDetectTask.addOnSuccessListener(OnSuccessListener { languageDetected ->
progressDialog!!.setMessage("Initializing text translation..")
// Processing logic for detection success.
textTranslate(languageDetected, textRecognized!!, bitmap)
}).addOnFailureListener(object : OnFailureListener {
override fun onFailure(e: Exception) {
// Processing logic for detection failure.
Log.e("TAG", "Lang detect error:" + e.message)
}
})
} else {
progressDialog!!.dismiss()
showErrorDialog("Failed to recognize text.")
}
}
}).addOnFailureListener(object : OnFailureListener {
override fun onFailure(e: Exception) {
Log.e("TAG", "#==>" + e.message)
}
})
}
private fun showErrorDialog(msg: String) {
val alertDialog = AlertDialog.Builder(this).create()
alertDialog.setTitle("Error")
alertDialog.setMessage(msg)
alertDialog.setButton(
AlertDialog.BUTTON_POSITIVE,
"OK",
object : DialogInterface.OnClickListener {
override fun onClick(dialog: DialogInterface, which: Int) {
dialog.dismiss()
}
})
alertDialog.show()
}
private fun textTranslate(languageDetected: String, textRecognized: String, uri: Bitmap?) {
MLApplication.initialize(application)
MLApplication.getInstance().apiKey = Constants.API_KEY
// Create an offline translator.
val setting =
MLLocalTranslateSetting.Factory() // Set the source language code. The ISO 639-1 standard is used. This parameter is mandatory. If this parameter is not set, an error may occur.
.setSourceLangCode(languageDetected) // Set the target language code. The ISO 639-1 standard is used. This parameter is mandatory. If this parameter is not set, an error may occur.
.setTargetLangCode("en")
.create()
myLocalTranslator = MLTranslatorFactory.getInstance().getLocalTranslator(setting)
// Set the model download policy.
val downloadStrategy = MLModelDownloadStrategy.Factory()
.needWifi() // It is recommended that you download the package in a Wi-Fi environment.
.create()
// Create a download progress listener.
val modelDownloadListener: MLModelDownloadListener = object : MLModelDownloadListener {
override fun onProcess(alreadyDownLength: Long, totalLength: Long) {
runOnUiThread(object : Runnable {
override fun run() {
// Display the download progress or perform other operations.
}
})
}
}
myLocalTranslator!!.preparedModel(downloadStrategy, modelDownloadListener)
.addOnSuccessListener(object : OnSuccessListener<Void?> {
override fun onSuccess(aVoid: Void?) {
// Called when the model package is successfully downloaded.
// input is a string of less than 5000 characters.
val task = myLocalTranslator!!.asyncTranslate(textRecognized)
// Before translation, ensure that the models have been successfully downloaded.
task.addOnSuccessListener(object : OnSuccessListener<String> {
override fun onSuccess(translated: String) {
// Processing logic for detection success.
result.clear()
result.add(languageDetected.trim { it <= ' ' })
result.add(textRecognized.trim { it <= ' ' })
result.add(translated.trim { it <= ' ' })
loginViewModel!!.setImage(uri!!)
loginViewModel!!.setTextRecongnized(result)
progressDialog!!.dismiss()
}
}).addOnFailureListener(object : OnFailureListener {
override fun onFailure(e: Exception) {
// Processing logic for detection failure.
progressDialog!!.dismiss()
}
})
}
}).addOnFailureListener(object : OnFailureListener {
override fun onFailure(e: Exception) {
// Called when the model package fails to be downloaded.
progressDialog!!.dismiss()
}
})
}
private fun createMLTextAnalyzer() {
val setting = MLLocalTextSetting.Factory()
.setOCRMode(MLLocalTextSetting.OCR_DETECT_MODE)
.create()
mTextAnalyzer = MLAnalyzerFactory.getInstance().getLocalTextAnalyzer(setting)
}
override fun onStop() {
if (myLocalLangDetector != null) {
myLocalLangDetector!!.stop()
}
if (myLocalTranslator != null) {
myLocalTranslator!!.stop()
}
if (progressDialog != null) {
progressDialog!!.dismiss()
}
super.onStop()
}
companion object {
var TAG = "TAG"
}
}
LoginViewModel.kt
Java:
package com.huawei.hms.knowmyboard.dtse.activity.viewmodel
import android.app.Application
import com.huawei.hms.support.account.service.AccountAuthService
import android.graphics.Bitmap
import com.huawei.hms.location.LocationResult
import com.huawei.hms.site.api.model.Site
import android.widget.Toast
import androidx.lifecycle.AndroidViewModel
import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
import com.huawei.hms.common.ApiException
import com.huawei.hms.knowmyboard.dtse.R
import com.huawei.hms.support.account.request.AccountAuthParams
import com.huawei.hms.support.account.request.AccountAuthParamsHelper
import com.huawei.hms.support.account.AccountAuthManager
import com.huawei.hms.knowmyboard.dtse.activity.app.MyApplication
import java.util.ArrayList
class LoginViewModel(application: Application) : AndroidViewModel(application) {
var service: AccountAuthService? = null
val message = MutableLiveData<String>()
val textRecongnized = MutableLiveData<ArrayList<String>>()
val imagePath = MutableLiveData<Bitmap>()
val locationResult = MutableLiveData<LocationResult>()
val siteSelected = MutableLiveData<Site>()
fun getSiteSelected(): LiveData<Site> {
return siteSelected
}
fun setSiteSelected(siteSelected: Site) {
this.siteSelected.value = siteSelected
}
fun sendData(msg: String) {
message.value = msg
}
fun getMessage(): LiveData<String> {
return message
}
fun setImage(imagePath: Bitmap) {
this.imagePath.value = imagePath
}
fun setLocationResult(locationResult: LocationResult) {
this.locationResult.value = locationResult
}
fun setTextRecongnized(textRecongnized: ArrayList<String>) {
this.textRecongnized.value = textRecongnized
}
fun logoutHuaweiID() {
if (service != null) {
service!!.signOut()
sendData("KnowMyBoard")
Toast.makeText(getApplication(), "You are logged out from Huawei ID", Toast.LENGTH_LONG)
.show()
}
}
fun loginClicked() {
val authParams =
AccountAuthParamsHelper(AccountAuthParams.DEFAULT_AUTH_REQUEST_PARAM).setAuthorizationCode()
.createParams()
service = AccountAuthManager.getService(MyApplication.activity, authParams)
MyApplication.activity!!.startActivityForResult(service!!.signInIntent, 8888)
}
fun cancelAuthorization() {
if (service != null) {
// service indicates the AccountAuthService instance generated using the getService method during the sign-in authorization.
service!!.cancelAuthorization().addOnCompleteListener { task ->
if (task.isSuccessful) {
// Processing after a successful authorization cancellation.
sendData(getApplication<Application>().resources.getResourceName(R.string.app_name))
Toast.makeText(getApplication(), "Cancelled authorization", Toast.LENGTH_LONG)
.show()
} else {
// Handle the exception.
val exception = task.exception
if (exception is ApiException) {
val statusCode = exception.statusCode
Toast.makeText(
getApplication(),
"Failed to cancel authorization. status code $statusCode",
Toast.LENGTH_LONG
).show()
}
}
}
} else {
Toast.makeText(getApplication(), "Login required", Toast.LENGTH_LONG).show()
}
}
}
SearchFragment.kt
Java:
package com.huawei.hms.knowmyboard.dtse.activity.fragments
import androidx.navigation.Navigation.findNavController
import com.huawei.hms.knowmyboard.dtse.activity.viewmodel.LoginViewModel
import androidx.navigation.NavController
import com.huawei.hms.site.api.SearchService
import com.huawei.hms.knowmyboard.dtse.activity.adapter.SitesAdapter
import com.huawei.hms.site.api.model.Site
import com.huawei.hms.location.LocationResult
import com.huawei.hms.knowmyboard.dtse.activity.intefaces.ItemClickListener
import android.view.WindowManager
import android.view.LayoutInflater
import android.view.ViewGroup
import android.os.Bundle
import android.util.Log
import android.view.View
import androidx.appcompat.widget.SearchView
import androidx.databinding.DataBindingUtil
import androidx.fragment.app.Fragment
import androidx.lifecycle.ViewModelProvider
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import com.huawei.hms.knowmyboard.dtse.R
import com.huawei.hms.knowmyboard.dtse.activity.util.Constants
import com.huawei.hms.knowmyboard.dtse.databinding.FragmentSearchBinding
import com.huawei.hms.site.api.SearchServiceFactory
import com.huawei.hms.site.api.model.TextSearchRequest
import com.huawei.hms.site.api.model.Coordinate
import com.huawei.hms.site.api.SearchResultListener
import com.huawei.hms.site.api.model.TextSearchResponse
import com.huawei.hms.site.api.model.SearchStatus
import com.huawei.hms.site.api.model.NearbySearchRequest
import com.huawei.hms.site.api.model.HwLocationType
import com.huawei.hms.site.api.model.NearbySearchResponse
import java.io.UnsupportedEncodingException
import java.lang.Exception
import java.net.URLEncoder
import java.util.ArrayList
class SearchFragment : Fragment() {
var binding: FragmentSearchBinding? = null
var loginViewModel: LoginViewModel? = null
//View view;
var navController: NavController? = null
private var searchService: SearchService? = null
var adapter: SitesAdapter? = null
var siteArrayList = ArrayList<Site>()
var locationResult: LocationResult? = null
/* var siteClicklistener = ItemClickListener { vh, site, pos ->
requireActivity().window.setSoftInputMode(
WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_HIDDEN
)
loginViewModel!!.setSiteSelected(site)
navController!!.navigate(R.id.loginFragment)
}*/
var siteClicklistener = object : ItemClickListener{
override fun onItemClicked(vh: RecyclerView.ViewHolder?, item: Site?, pos: Int) {
requireActivity().window.setSoftInputMode(
WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_HIDDEN
)
loginViewModel!!.setSiteSelected(item!!)
navController!!.navigate(R.id.loginFragment)
}
}
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
requireActivity().window.setSoftInputMode(
WindowManager.LayoutParams.SOFT_INPUT_STATE_VISIBLE
)
binding = DataBindingUtil.inflate(inflater, R.layout.fragment_search, container, false)
loginViewModel = ViewModelProvider(requireActivity()).get(
LoginViewModel::class.java
)
val searchView = binding!!.edSearch
val recyclerView = binding!!.suggestionRv
navController = findNavController(requireActivity(), R.id.nav_host_fragment)
searchView.isFocusable = true
searchView.onActionViewExpanded()
adapter = SitesAdapter(siteArrayList, context, siteClicklistener)
recyclerView.adapter = adapter
recyclerView.layoutManager = LinearLayoutManager(context)
recyclerView.setHasFixedSize(true)
loginViewModel!!.locationResult.observeForever { locationResult1 ->
locationResult = locationResult1
}
searchView.setOnQueryTextListener(object : SearchView.OnQueryTextListener {
override fun onQueryTextSubmit(query: String): Boolean {
return false
}
override fun onQueryTextChange(newText: String): Boolean {
if (newText.length > 4) {
nearByPlacesSearch(newText)
}
return false
}
})
return binding!!.root
}
fun keywordSearch(search: String?) {
try {
val key = URLEncoder.encode(Constants.API_KEY, "UTF-8")
// Instantiate the SearchService object.
searchService = SearchServiceFactory.create(context, key)
// Create a request body.
val request = TextSearchRequest()
request.query = search
if (locationResult != null) {
val location = Coordinate(
locationResult!!.lastHWLocation.latitude,
locationResult!!.lastHWLocation.longitude
)
request.location = location
}
request.radius = 1000
//request.setHwPoiType(HwLocationType.HOTEL_MOTEL);
request.countryCode = "IN"
request.language = "en"
request.pageIndex = 1
request.pageSize = 5
request.isChildren = false
// request.setCountries(Arrays.asList("en", "fr", "cn", "de", "ko","in"));
// Create a search result listener.
val resultListener: SearchResultListener<TextSearchResponse?> =
object : SearchResultListener<TextSearchResponse?> {
// Return search results upon a successful search.
override fun onSearchResult(results: TextSearchResponse?) {
if (results == null || results.totalCount <= 0) {
return
}
val sites = results.sites
if (sites == null || sites.size == 0) {
return
}
siteArrayList.clear()
for (site in sites) {
siteArrayList.add(site)
}
siteArrayList.addAll(sites)
adapter!!.notifyDataSetChanged()
}
// Return the result code and description upon a search exception.
override fun onSearchError(status: SearchStatus) {
Log.i("TAG", "Error : " + status.errorCode + " " + status.errorMessage)
}
}
// Call the keyword search API.
searchService!!.textSearch(request, resultListener)
} catch (e: UnsupportedEncodingException) {
e.printStackTrace()
}
}
fun nearByPlacesSearch(newText: String?) {
try {
val key = URLEncoder.encode(Constants.API_KEY, "UTF-8")
// Instantiate the SearchService object.
searchService = SearchServiceFactory.create(context, key)
// Create a request body.
val request = NearbySearchRequest()
if (locationResult != null) {
val location = Coordinate(
locationResult!!.lastHWLocation.latitude,
locationResult!!.lastHWLocation.longitude
)
request.location = location
}
request.query = newText
request.radius = 1000
request.hwPoiType = HwLocationType.ADDRESS
request.language = "en"
request.pageIndex = 1
request.pageSize = 5
request.strictBounds = false
// Create a search result listener.
val resultListener: SearchResultListener<NearbySearchResponse?> =
object : SearchResultListener<NearbySearchResponse?> {
// Return search results upon a successful search.
override fun onSearchResult(results: NearbySearchResponse?) {
if (results == null || results.totalCount <= 0) {
return
}
val sites = results.sites
if (sites == null || sites.size == 0) {
return
}
siteArrayList.clear()
for (site in sites) {
siteArrayList.add(site)
}
siteArrayList.addAll(sites)
adapter!!.notifyDataSetChanged()
}
// Return the result code and description upon a search exception.
override fun onSearchError(status: SearchStatus) {
Log.i("TAG", "Error : " + status.errorCode + " " + status.errorMessage)
}
}
// Call the nearby place search API.
searchService!!.nearbySearch(request, resultListener)
} catch (e: Exception) {
e.printStackTrace()
}
}
}
RequestLocationData.kt
Java:
package com.huawei.hms.knowmyboard.dtse.activity.util
import android.Manifest
import com.huawei.hms.knowmyboard.dtse.activity.viewmodel.LoginViewModel
import android.app.Activity
import android.content.Context
import android.os.Build
import android.content.pm.PackageManager
import android.os.Looper
import android.location.Geocoder
import android.util.Log
import androidx.annotation.RequiresApi
import androidx.core.app.ActivityCompat
import androidx.fragment.app.FragmentActivity
import com.huawei.hms.location.*
import java.io.IOException
import java.lang.StringBuilder
import java.util.*
class RequestLocationData(
context: Context?,
activity: FragmentActivity?,
loginViewModel: LoginViewModel?
) {
private var settingsClient: SettingsClient? = null
private var isLocationSettingSuccess = 0
private var myLocationRequest: LocationRequest? = null
// Define a fusedLocationProviderClient object.
private var fusedLocationProviderClient: FusedLocationProviderClient? = null
private var myLocationCallback: LocationCallback? = null
var context: Context? = null
var activity: Activity? = null
private var locationResult: LocationResult? = null
var loginViewModel: LoginViewModel? = null
fun initFusionLocationProviderClint() {
// Instantiate the fusedLocationProviderClient object.
fusedLocationProviderClient = LocationServices.getFusedLocationProviderClient(activity)
this.settingsClient = LocationServices.getSettingsClient(activity)
}
fun checkDeviceLocationSettings() {
val builder = LocationSettingsRequest.Builder()
myLocationRequest = LocationRequest()
builder.addLocationRequest(myLocationRequest)
val locationSettingsRequest = builder.build()
// Check the device location settings.
settingsClient!!.checkLocationSettings(locationSettingsRequest) // Define the listener for success in calling the API for checking device location settings.
.addOnSuccessListener { locationSettingsResponse: LocationSettingsResponse ->
val locationSettingsStates = locationSettingsResponse.locationSettingsStates
val stringBuilder = StringBuilder()
// Check whether the location function is enabled.
stringBuilder.append(",\nisLocationUsable=")
.append(locationSettingsStates.isLocationUsable)
// Check whether HMS Core (APK) is available.
stringBuilder.append(",\nisHMSLocationUsable=")
.append(locationSettingsStates.isHMSLocationUsable)
Log.i(TAG, "checkLocationSetting onComplete:$stringBuilder")
// Set the location type.
myLocationRequest!!.priority = LocationRequest.PRIORITY_HIGH_ACCURACY
// Set the number of location updates to 1.
myLocationRequest!!.numUpdates = 1
isLocationSettingSuccess = 1
} // Define callback for failure in checking the device location settings.
.addOnFailureListener { e -> Log.i(TAG, "checkLocationSetting onFailure:" + e.message) }
}
@RequiresApi(Build.VERSION_CODES.S)
fun checkPermission() {
// Dynamically apply for required permissions if the API level is 28 or lower.
if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.P) {
Log.i(TAG, "android sdk <= 28 Q")
if (ActivityCompat.checkSelfPermission(
context!!,
Manifest.permission.ACCESS_FINE_LOCATION
) != PackageManager.PERMISSION_GRANTED
&& ActivityCompat.checkSelfPermission(
context!!,
Manifest.permission.ACCESS_COARSE_LOCATION
) != PackageManager.PERMISSION_GRANTED
) {
val strings = arrayOf(
Manifest.permission.CAMERA,
Manifest.permission.MANAGE_MEDIA,
Manifest.permission.MEDIA_CONTENT_CONTROL,
Manifest.permission.ACCESS_FINE_LOCATION,
Manifest.permission.ACCESS_COARSE_LOCATION
)
ActivityCompat.requestPermissions(activity!!, strings, 1)
}
} else {
// Dynamically apply for the android.permission.ACCESS_BACKGROUND_LOCATION permission in addition to the preceding permissions if the API level is higher than 28.
if (ActivityCompat.checkSelfPermission(
activity!!,
Manifest.permission.ACCESS_FINE_LOCATION
) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(
context!!,
Manifest.permission.ACCESS_COARSE_LOCATION
) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(
context!!,
"android.permission.ACCESS_BACKGROUND_LOCATION"
) != PackageManager.PERMISSION_GRANTED
) {
val strings = arrayOf(
Manifest.permission.CAMERA,
Manifest.permission.ACCESS_FINE_LOCATION,
Manifest.permission.ACCESS_COARSE_LOCATION,
Manifest.permission.MEDIA_CONTENT_CONTROL,
Manifest.permission.MANAGE_MEDIA,
"android.permission.ACCESS_BACKGROUND_LOCATION"
)
ActivityCompat.requestPermissions(activity!!, strings, 2)
}
}
}
fun refreshLocation(): LocationResult? {
Log.d(TAG, "Refreshing location")
if (isLocationSettingSuccess == 1) {
myLocationCallback = object : LocationCallback() {
private var locationResult: LocationResult? = null
override fun onLocationResult(locationResult: LocationResult) {
if (locationResult != null) {
// Gson gson = new Gson();
//Log.d(TAG, " Location data :" + locationResult.getLastLocation().getLatitude() + " : " + locationResult.getLastLocation().getLongitude());
//Log.d(TAG, " Location data :" + gson.toJson(locationResult.getLastHWLocation()));
//Log.d(TAG, " Location data :" + locationResult.getLastHWLocation().getCountryName());
Log.d(TAG, " Location data :" + locationResult.lastHWLocation.latitude)
Log.d(TAG, " Location data :" + locationResult.lastHWLocation.longitude)
// binding.textDetected.setText("Latitude " + locationResult.getLastHWLocation().getLatitude() + " Longitude " + locationResult.getLastHWLocation().getLongitude());
//getGeoCoderValues(locationResult.getLastHWLocation().getLatitude(),locationResult.getLastHWLocation().getLongitude());
this.locationResult = locationResult
loginViewModel!!.setLocationResult(locationResult)
}
}
}
fusedLocationProviderClient!!.requestLocationUpdates(
myLocationRequest,
myLocationCallback,
Looper.getMainLooper()
)
} else {
Log.d(TAG, "Failed to get location settings")
}
return locationResult
}
fun disableLocationData() {
fusedLocationProviderClient!!.disableBackgroundLocation()
fusedLocationProviderClient!!.removeLocationUpdates(myLocationCallback)
}
private fun getGeoCoderValues(latitude: Double, longitude: Double) {
getAddress(context, latitude, longitude)
/* Geocoder geocoder;
List<Address> addresses;
Locale locale = new Locale("en", "IN");
geocoder = new Geocoder(getContext(), locale);
try {
addresses = geocoder.getFromLocation(latitude, longitude, 1); // Here 1 represent max location result to returned, by documents it recommended 1 to 5
Gson gson=new Gson();
Log.d(TAG,"Geo coder :"+gson.toJson(addresses));
String address = addresses.get(0).getAddressLine(0); // If any additional address line present than only, check with max available address lines by getMaxAddressLineIndex()
String city = addresses.get(0).getLocality();
String state = addresses.get(0).getAdminArea();
String country = addresses.get(0).getCountryName();
String postalCode = addresses.get(0).getPostalCode();
String knownName = addresses.get(0).getFeatureName();
} catch (IOException e) {
e.printStackTrace();
Log.e(TAG,"Error while fetching Geo coder :"+e.getMessage());
}*/
/* Locale locale = new Locale("en", "IN");
GeocoderService geocoderService =
LocationServices.getGeocoderService(getActivity().getBaseContext(), locale);
// Request reverse geocoding.
GetFromLocationRequest getFromLocationRequest = new GetFromLocationRequest(latitude, longitude, 5);
// Initiate reverse geocoding.
geocoderService.getFromLocation(getFromLocationRequest)
.addOnSuccessListener(hwLocation -> {
Gson gson=new Gson();
Log.d(TAG,"Geo coder :"+gson.toJson(hwLocation));
})
.addOnFailureListener(e -> {
Log.e(TAG,"Error while fetching Geo coder :"+e.getMessage());
});*/
}
companion object {
var TAG = "TAG"
fun getAddress(context: Context?, LATITUDE: Double, LONGITUDE: Double) {
//Set Address
try {
val geocoder = Geocoder(context, Locale.getDefault())
val addresses = geocoder.getFromLocation(LATITUDE, LONGITUDE, 1)
if (addresses != null && addresses.size > 0) {
val address =
addresses[0].getAddressLine(0) // If any additional address line present than only, check with max available address lines by getMaxAddressLineIndex()
val city = addresses[0].locality
val state = addresses[0].adminArea
val country = addresses[0].countryName
val postalCode = addresses[0].postalCode
val knownName = addresses[0].featureName // Only if available else return NULL
Log.d(TAG, "getAddress: address$address")
Log.d(TAG, "getAddress: city$city")
Log.d(TAG, "getAddress: state$state")
Log.d(TAG, "getAddress: postalCode$postalCode")
Log.d(TAG, "getAddress: knownName$knownName")
}
} catch (e: IOException) {
e.printStackTrace()
Log.e(TAG, "Error while fetching Geo coder :" + e.message)
}
}
}
init {
[email protected] = context
[email protected] = activity
[email protected] = loginViewModel
}
}
navigation_graph.xml
XML:
<?xml version="1.0" encoding="utf-8"?>
<navigation 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:id="@+id/navigation_graph"
app:startDestination="@id/loginFragment">
<fragment
android:id="@+id/loginFragment"
android:name="com.huawei.hms.knowmyboard.dtse.activity.fragments.LoginFragment"
android:label="LoginFragment"/>
<fragment
android:id="@+id/mainFragment"
android:name="com.huawei.hms.knowmyboard.dtse.activity.fragments.MainFragment"
android:label="MainFragment"/>
<fragment
android:id="@+id/searchFragment"
android:name="com.huawei.hms.knowmyboard.dtse.activity.fragments.SearchFragment"
android:label="fragment_search"
tools:layout="@layout/fragment_search" />
</navigation>
bottom_navigation_menu.xml
XML:
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<item
android:id="@+id/searchFragment"
android:icon="@android:drawable/ic_menu_search"
android:title="@string/search" />
<item
android:id="@+id/loginFragment"
android:icon="@android:drawable/ic_menu_agenda"
android:title="Home" />
<item
android:id="@+id/mainFragment"
app:showAsAction="always"
android:icon="@android:drawable/ic_menu_gallery"
android:title="Gallery" />
</menu>
Result
{
"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"
}
Tricks and Tips
Makes sure that agconnect-services.json file added.
Make sure required dependencies are added
Make sure that service is enabled in AGC
Enable data binding in gradle.build file
Make sure bottom navigation id's should be same as fragment id's in navigation graph
Conclusion
In this article, we have learnt how to integrate Huawei Site Kit, Map kit, Location kit in Android application KnowMyBoard. Hoping that the Map kit capabilities are helpful to you as well, like this sample, you can make use of Site kit as per your requirement.
Reference
Map Kit – Training video
Site Kit – Training video