Search News with Voice (Search Kit — ML Kit(ASR)— Network Kit) - Huawei Developers

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

Related

Location Kit Integration in Unity - Official Plugin (Huawei HMS Core App Services)

More information like this, you can visit HUAWEI Developer Forum​
Original link: https://forums.developer.huawei.com/forumPortal/en/topicview?tid=0201350575696000176&fid=0101187876626530001
Introduction:
In this article, we will cover Integration of Location Kit in Unity Project using Official Plugin (Huawei HMS Core App Services).
{
"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"
}
Requirements:
1. Unity Editor
2. Huawei device
3. Visual Studio
Output:
Fetch and show the users current location (Latitude and Longitude) using Huawei Location Kit.
Follows the steps.
1. Create Unity Project.
Click unity icon.
Click NEW, select 3D, Project Name and Location.
Click CREATE, as follows.
2. Click Asset Store, search Huawei HMS Core App Services and click Import, as follows.
3. Once import is successful, verify directory in Assets > Huawei HMS Core App Services path, as follows.
4. Click Console and create a New Project.
5. Choose Project Settings > Player and edit the required options in Publishing Settings, as follows.
6. Verify the files created in Step 5.
7. Download agconnect-services.json and copy to Assets/Plugins/Android, as follows.
8. Update the Package Name.
9. Open LauncherTemplate.gradle and add below line
Code:
implementation 'com.android.support:appcompat-v7:28.0.0'
10. Open AndroidManifest file & Add below permissions.
Code:
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
<uses-permission android:name="android.permission.ACCESS_BACKGROUND_LOCATION"/>
11. Add Receiver Like shown below in Android Manifest File.
Code:
<receiver
android:name="com.unity.hms.location.LocationBroadcastReceiver"
android:exported="true">
</receiver>
12. Open "baseProjectTemplate.gradle" and add lines, as follows.
Code:
maven {url 'https://developer.huawei.com/repo/'}
13. Open "mainTemplate.gradle" and add lines like shown below
Code:
implementation 'com.huawei.hms:location:5.0.0.301'
implementation 'com.huawei.hms:ads-lite:13.4.30.301'
14. Scripting, create two classes.
TestClass.cs
Code:
using System.Collections;
using System.Collections.Generic;
using HuaweiHms;
using UnityEngine;
public class TestClass : IBroadcastReceiver
{
override
public void onReceive(Context arg0, Intent arg1)
{
Debug.LogError("kamal onReceive--->");
}
}
RegisterReceiver.cs
Code:
using System.Collections;
using System.Collections.Generic;
using HuaweiHms;
using UnityEngine;
using UnityEngine.UI;
public class RegisterReceiver : MonoBehaviour
{
static FusedLocationProviderClient fusedLocationProviderClient;
static LocationRequest locatinoRequest;
public Text latitude;
public Text longitude;
private void Awake()
{
//AdListener add = new AdListener();
TestClass receiver = new TestClass();
BroadcastRegister.CreateLocationReceiver(receiver);
Debug.LogError("kamal RegisterReceiver--->");
//LocationRequest request = new LocationRequest();
//request.setInterval(10000);
//request.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
locatinoRequest = LocationRequest.create();
locatinoRequest.setInterval(10000);
locatinoRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
LocationSettingsRequest.Builder builder = new LocationSettingsRequest.Builder();
builder.addLocationRequest(locatinoRequest);
LocationSettingsRequest locationSettingsRequest = builder.build();
Activity act = new Activity();
//Context context = new Context();
fusedLocationProviderClient = LocationServices.getFusedLocationProviderClient(act);
SettingsClient settingsClient = LocationServices.getSettingsClient(act);
settingsClient.checkLocationSettings(locationSettingsRequest)
.addOnSuccessListener(new OnSuccessListenerTemp(this))
.addOnFailureListener(new OnFailureListenerTemp());
Debug.LogError("kamal RegisterReceiver request send--->");
}
class OnSuccessListenerTemp : OnSuccessListener
{
private RegisterReceiver registerReceiver;
public OnSuccessListenerTemp(RegisterReceiver registerReceiver)
{
this.registerReceiver = registerReceiver;
}
public override void onSuccess(AndroidJavaObject arg0) {
Debug.LogError("kamal onSuccess 0--->");
fusedLocationProviderClient.requestLocationUpdates(locatinoRequest, new OnLocationCallback(this.registerReceiver), Looper.getMainLooper())
.addOnSuccessListener(new OnReqSuccessListenerTemp())
.addOnFailureListener(new OnReqFailureListenerTemp())
;
}
};
class OnReqSuccessListenerTemp : OnSuccessListener
{
public override void onSuccess(AndroidJavaObject arg0)
{
Debug.LogError("kamal onSuccess 1--->");
}
};
class OnReqFailureListenerTemp : OnFailureListener
{
public override void onFailure(Exception arg0)
{
Debug.LogError("kamal onFailure 2--->");
}
}
class OnLocationCallback : LocationCallback {
private RegisterReceiver registerReceiver;
public OnLocationCallback(RegisterReceiver registerReceiver)
{
this.registerReceiver = registerReceiver;
}
public override void onLocationAvailability(LocationAvailability arg0) {
Debug.LogError("kamal onLocationAvailability 0--->");
}
public override void onLocationResult(LocationResult locationResult) {
Location location = locationResult.getLastLocation();
HWLocation hWLocation = locationResult.getLastHWLocation();
Debug.LogError("kamal onLocationResult found location--->");
if (location != null) {
Debug.LogError("kamal getLatitude--->" + location.getLatitude() + "<-getLongitude->" + location.getLongitude());
//latitude.text = "Latitude-->" + location.getLatitude();
//longitude.text = "Longitude-->" + location.getLongitude() ;
//RegisterReceiver.this.updateData(location);
registerReceiver.updateData(location);
}
if (hWLocation != null)
{
string country = hWLocation.getCountryName();
string city = hWLocation.getCity();
string countryCode = hWLocation.getCountryCode();
string dd = hWLocation.getPostalCode();
Debug.LogError("kamal country--->"+country + "<-city->"+city+ "<-countrycode->"+countryCode+"<-postal code->"+dd);
}
else {
Debug.LogError("kamal onLocationResult found location hWLocation is null--->");
}
}
}
private void updateData(Location location) {
latitude.text = "Latitude-->" + location.getLatitude();
longitude.text = "Longitude-->" + location.getLongitude() ;
}
class OnFailureListenerTemp : OnFailureListener {
public override void onFailure(Exception arg0) {
Debug.LogError("kamal onFailure--->");
}
}
// Start is called before the first frame update
void Start()
{
}
// Update is called once per frame
void Update()
{
}
}
15. Code explanation, follow below URL.
https://developer.huawei.com/consumer/en/codelab/HMSLocationKit/index.html#5
16. Run Attach Script to Scene, create two Text Views and assign them to script for showing latitude and longitude.
17. Run the project and enable location permission manually, as its demo I did not do it programmatically.
Conclusion
Latitude and Longitude both are coming on game screen, as shown below
References
Integrate Unity & Account Kit
https://forums.developer.huawei.com/forumPortal/en/topicview?tid=0202334275608690050&fid=0101187876626530001
Integrate Unity & In App purchase
https://forums.developer.huawei.com/forumPortal/en/topicview?tid=0201335993101470045&fid=0101187876626530001
HMS Ads integration with Unity
https://forums.developer.huawei.com/forumPortal/en/topicview?tid=0201337158850280060&fid=0101187876626530001

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

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

Getting Latest Corona News with Huawei Search Kit

{
"lightbox_close": "Close",
"lightbox_next": "Next",
"lightbox_previous": "Previous",
"lightbox_error": "The requested content cannot be loaded. Please try again later.",
"lightbox_start_slideshow": "Start slideshow",
"lightbox_stop_slideshow": "Stop slideshow",
"lightbox_full_screen": "Full screen",
"lightbox_thumbnails": "Thumbnails",
"lightbox_download": "Download",
"lightbox_share": "Share",
"lightbox_zoom": "Zoom",
"lightbox_new_window": "New window",
"lightbox_toggle_sidebar": "Toggle sidebar"
}
Huawei Search Kit includes device-side SDK and cloud-side APIs to use all features of Petal Search capabilities. It helps developers to integrate mobile app search experience into their application.
Huawei Search Kit offers to developers so much different and helpful features. It decreases our development cost with SDKs and APIs, it returns responses quickly and it helps us to develop our application faster.
As a developer, we have some responsibilities and function restrictions while using Huawei Search Kit. If you would like to learn about these responsibilities and function restrictions, I recommend you to visit following website.
https://developer.huawei.com/consum.../HMSCore-Guides/introduction-0000001055591730
Also, Huawei Search Kit supports limited countries and regions. If you wonder about these countries and regions, you can visit the following website.
https://developer.huawei.com/consum...HMSCore-Guides-V5/regions-0000001056871703-V5
How to use Huawei Search Kit?
First of all, we need to create an app on AppGallery Connect and add related details about HMS Core to our project.
If you don’t know about how to integrate HMS Core to our project, you can learn all details from following Medium article.
https://medium.com/huawei-developers/android-integrating-your-apps-with-huawei-hms-core-1f1e2a090e98
After we have done all steps in above Medium article, we can focus on special steps of integrating Huawei Search Kit.
Our minSdkVersion should be 24 at minimum.
We need to add following dependency to our app level build.gradle file.
Code:
implementation "com.huawei.hms:searchkit:5.0.4.303"
Then, we need to do some changes on AppGallery Connect. We need to define a data storage location on AppGallery Connect.
Note: If we don’t define a data storage location, all responses will return null.
We need to initialize the SearchKit instance on our application which we have extended from android.app.Application class. To initialize the SearchKit instance, we need to set the app id on second parameter which has mentioned as Constants.APP_ID.
While adding our application class to AndroidManifest.xml file, we need to set android:usesCleartextTraffic as true. You can do all these steps as mentioned in red rectangles.
Getting Access Token
For each request on Search Kit, we need to use access token. I prefer to get this access token on splash screen of the application. Thus, we will be able to save access token and save it with SharedPreferences.
First of all, we need to create our methods and objects about network operations. I am using Koin Framework for dependency injection on this project.
For creating objects about network operations, I have created following single objects and methods.
Note: In above picture, I have initialized the koin framework and added network module. Check this step to use this module in the app.
Java:
val networkModule = module {
single { getOkHttpClient(androidContext()) }
single { getRetrofit(get()) }
single { getService<AccessTokenService>(get()) }
}
fun getRetrofit(okHttpClient: OkHttpClient): Retrofit {
return Retrofit.Builder().baseUrl("https://oauth-login.cloud.huawei.com/")
.client(okHttpClient)
.addConverterFactory(GsonConverterFactory.create())
.build()
}
fun getOkHttpClient(context: Context): OkHttpClient {
return OkHttpClient().newBuilder()
.sslSocketFactory(SecureSSLSocketFactory.getInstance(context), SecureX509TrustManager(context))
.hostnameVerifier(StrictHostnameVerifier())
.readTimeout(10, TimeUnit.SECONDS)
.connectTimeout(1, TimeUnit.SECONDS)
.retryOnConnectionFailure(true)
.build()
}
inline fun <reified T> getService(retrofit: Retrofit): T = retrofit.create(T::class.java)
We have defined methods to create OkHttpClient and Retrofit objects. These objects have used as single to create Singleton objects. Also, we have defined one generic method to use Retrofit with our services.
To get an access token, our base URL will be “https://oauth-login.cloud.huawei.com/".
To get response from access token request, we need to define an object for response. The best way to do that is creating data class which is as shown in the below.
Java:
data class AccessTokenResponse(
@SerializedName("access_token") val accessToken: String?,
@SerializedName("expires_in") val expiresIn: Int?,
@SerializedName("token_type") val tokenType: String?
)
Now, all we need to do is, creating an interface to send requests with Retrofit. To get access token, our total URL is “https://oauth-login.cloud.huawei.com/oauth2/v3/token". We need to send 3 parameters as x-www-form-url encoded. Let’s examine these parameters.
grant_type: This parameter will not change depends on our application. Value should be, “client_credentials”.
client_id: This parameter will be app id of our project.
client_secret: This parameter will be app secret of our project.
Java:
interface AccessTokenService {
@FormUrlEncoded
@POST("oauth2/v3/token")
fun getAccessToken(
@Field("grant_type") grantType: String,
@Field("client_id") appId: String,
@Field("client_secret") clientSecret: String
): Call<AccessTokenResponse>
}
Now, everything is ready to get an access token. We just need to send the request and save the access token with SharedPreferences.
To work with SharedPreferences, I have created a helper class as shown in the below.
Java:
class CacheHelper {
companion object {
private lateinit var instance: CacheHelper
private var gson: Gson = Gson()
private const val PREFERENCES_NAME = BuildConfig.APPLICATION_ID
private const val PREFERENCES_MODE = AppCompatActivity.MODE_PRIVATE
fun getInstance(context: Context): CacheHelper {
instance = CacheHelper(context)
return instance
}
}
private var context: Context
private var sharedPreferences: SharedPreferences
private var sharedPreferencesEditor: SharedPreferences.Editor
private constructor(context: Context) {
this.context = context
sharedPreferences = this.context.getSharedPreferences(PREFERENCES_NAME, PREFERENCES_MODE)
sharedPreferencesEditor = sharedPreferences.edit()
}
fun putObject(key: String, `object`: Any) {
sharedPreferencesEditor.apply {
putString(key, gson.toJson(`object`))
commit()
}
}
fun <T> getObject(key: String, `object`: Class<T>): T? {
return sharedPreferences.getString(key, null)?.let {
gson.fromJson(it, `object`)
} ?: kotlin.run {
null
}
}
}
With the help of this class, we will be able to work with SharedPreferences easier.
Now, all we need to do it, sending request and getting access token.
Java:
object SearchKitService: KoinComponent {
private val accessTokenService: AccessTokenService by inject()
private val cacheHelper: CacheHelper by inject()
fun initAccessToken(requestListener: IRequestListener<Boolean, Boolean>) {
accessTokenService.getAccessToken(
"client_credentials",
Constants.APP_ID,
Constants.APP_SECRET
).enqueue(object: retrofit2.Callback<AccessTokenResponse> {
override fun onResponse(call: Call<AccessTokenResponse>, response: Response<AccessTokenResponse>) {
response.body()?.accessToken?.let { accessToken ->
cacheHelper.putObject(Constants.ACCESS_TOKEN_KEY, accessToken)
requestListener.onSuccess(true)
} ?: kotlin.run {
requestListener.onError(true)
}
}
override fun onFailure(call: Call<AccessTokenResponse>, t: Throwable) {
requestListener.onError(false)
}
})
}
}
If API returns as access token successfully, we will save this access token to device using SharedPreferences. And on our SplashFragment, we need to listen IRequestListener and if onSuccess method returns true, that means we got the access token successfully and we can navigate application to BrowserFragment.
Huawei Search Kit
In this article, I will give examples about News Search, Image Search and Video Search features of Huawei Search Kit.
In this article, I will give examples about News Search, Image Search and Video Search features of Huawei Search Kit.
To send requests for News Search, Image Search and Video Search, we need a CommonSearchRequest object.
In this app, I will get results about Corona in English. I have created the following method to return to CommonSearchRequest object.
Java:
private fun returnCommonRequest(): CommonSearchRequest {
return CommonSearchRequest().apply {
setQ("Corona Virus")
setLang(Language.ENGLISH)
setSregion(Region.WHOLEWORLD)
setPs(20)
setPn(1)
}
}
Here, we have setted some informations. Let’s examine this setter methods.
setQ(): Setting the keyword for search.
setLang(): Setting the language for search. Search Kit has it’s own model for language. If you would like examine this enum and learn about which Languages are supporting by Search Kit, you can visit the following website.
Huawei Search Kit — Language Model
setSregion(): Setting the region for search. Search Kit has it’s own model for region. If you would like examine this enum and learn about which Regions are supporting by Search Kit, you can visit the following website.
Huawei Search Kit — Region Model
setPn(): Setting the number about how much items will be in current page. The value ranges from 1 to 100, and the default value is 1.
setPs(): Setting the number of search results that will be returned on a page. The value ranges from 1 to 100, and the default value is 10.
Now, all we need to do is getting news, images, videos and show the results for these on the screen.
News Search
To get news, we can use the following method.
Java:
fun newsSearch(requestListener: IRequestListener<List<NewsItem>, String>) {
SearchKitInstance.getInstance().newsSearcher.setCredential(SearchKitService.accessToken)
var newsList = SearchKitInstance.getInstance().newsSearcher.search(SearchKitService.returnCommonRequest())
newsList?.getData()?.let { newsItems ->
requestListener.onSuccess(newsItems)
} ?: kotlin.run {
requestListener.onError("No value returned")
}
}
Image Search
To get images, we can use the following method.
Java:
fun imageSearch(requestListener: IRequestListener<List<ImageItem>, String>) {
SearchKitInstance.getInstance().imageSearcher.setCredential(SearchKitService.accessToken)
var imageList = SearchKitInstance.getInstance().imageSearcher.search(SearchKitService.returnCommonRequest())
imageList?.getData()?.let { imageItems ->
requestListener.onSuccess(imageItems)
} ?: kotlin.run {
requestListener.onError("No value returned")
}
}
Video Search
To get images, we can use the following method.
Java:
fun videoSearch(requestListener: IRequestListener<List<VideoItem>, String>) {
SearchKitInstance.getInstance().videoSearcher.setCredential(SearchKitService.accessToken)
var videoList = SearchKitInstance.getInstance().videoSearcher.search(SearchKitService.returnCommonRequest())
videoList?.getData()?.let { videoList ->
requestListener.onSuccess(videoList)
} ?: kotlin.run {
requestListener.onError("No value returned")
}
}
Showing on screen
All these results return a clickable url for each one. We can create an intent to open these URLs on the browser which has installed to device before.
To do that and other operations, I will share BrowserFragment codes for fragment and the SearchItemAdapter codes for recyclerview.
Java:
class BrowserFragment: Fragment() {
private lateinit var viewBinding: FragmentBrowserBinding
private lateinit var searchOptionsTextViews: ArrayList<TextView>
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
viewBinding = FragmentBrowserBinding.inflate(inflater, container, false)
searchOptionsTextViews = arrayListOf(viewBinding.news, viewBinding.images, viewBinding.videos)
return viewBinding.root
}
private fun setListeners() {
viewBinding.news.setOnClickListener { getNews() }
viewBinding.images.setOnClickListener { getImages() }
viewBinding.videos.setOnClickListener { getVideos() }
}
private fun getNews() {
SearchKitService.newsSearch(object: IRequestListener<List<NewsItem>, String>{
override fun onSuccess(newsItemList: List<NewsItem>) {
setupRecyclerView(newsItemList, viewBinding.news)
}
override fun onError(errorMessage: String) {
Toast.makeText(requireContext(), errorMessage, Toast.LENGTH_SHORT).show()
}
})
}
private fun getImages(){
SearchKitService.imageSearch(object: IRequestListener<List<ImageItem>, String>{
override fun onSuccess(imageItemList: List<ImageItem>) {
setupRecyclerView(imageItemList, viewBinding.images)
}
override fun onError(errorMessage: String) {
Toast.makeText(requireContext(), errorMessage, Toast.LENGTH_SHORT).show()
}
})
}
private fun getVideos() {
SearchKitService.videoSearch(object: IRequestListener<List<VideoItem>, String>{
override fun onSuccess(videoItemList: List<VideoItem>) {
setupRecyclerView(videoItemList, viewBinding.videos)
}
override fun onError(errorMessage: String) {
Toast.makeText(requireContext(), errorMessage, Toast.LENGTH_SHORT).show()
}
})
}
private val clickListener = object: IClickListener<String> {
override fun onClick(clickedInfo: String) {
var intent = Intent(Intent.ACTION_VIEW).apply {
data = Uri.parse(clickedInfo)
}
startActivity(intent)
}
}
private fun <T> setupRecyclerView(itemList: List<T>, selectedSearchOption: TextView) {
viewBinding.searchKitRecyclerView.apply {
layoutManager = LinearLayoutManager(requireContext())
adapter = SearchItemAdapter<T>(itemList, clickListener)
}
changeSelectedTextUi(selectedSearchOption)
}
private fun changeSelectedTextUi(selectedSearchOption: TextView) {
for (textView in searchOptionsTextViews)
if (textView == selectedSearchOption) {
textView.background = requireContext().getDrawable(R.drawable.selected_text)
} else {
textView.background = requireContext().getDrawable(R.drawable.unselected_text)
}
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
setListeners()
getNews()
}
}
Java:
class SearchItemAdapter<T>(private val searchItemList: List<T>,
private val clickListener: IClickListener<String>):
RecyclerView.Adapter<SearchItemAdapter.SearchItemHolder<T>>(){
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): SearchItemHolder<T> {
val itemBinding = ItemSearchBinding.inflate(LayoutInflater.from(parent.context), parent, false)
return SearchItemHolder<T>(itemBinding)
}
override fun onBindViewHolder(holder: SearchItemHolder<T>, position: Int) {
val item = searchItemList[position]
var isLast = (position == searchItemList.size - 1)
holder.bind(item, isLast, clickListener)
}
override fun getItemCount(): Int = searchItemList.size
override fun getItemViewType(position: Int): Int = position
class SearchItemHolder<T>(private val itemBinding: ItemSearchBinding): RecyclerView.ViewHolder(itemBinding.root) {
fun bind(item: T, isLast: Boolean, clickListener: IClickListener<String>) {
if (isLast)
itemBinding.itemSeparator.visibility = View.GONE
lateinit var clickUrl: String
var imageUrl = "https://www.who.int/images/default-source/infographics/who-emblem.png?sfvrsn=877bb56a_2"
when(item){
is NewsItem -> {
itemBinding.searchResultTitle.text = item.title
itemBinding.searchResultDetail.text = item.provider.siteName
clickUrl = item.clickUrl
item.provider.logo?.let { imageUrl = it }
}
is ImageItem -> {
itemBinding.searchResultTitle.text = item.title
clickUrl = item.clickUrl
item.sourceImage.image_content_url?.let { imageUrl = it }
}
is VideoItem -> {
itemBinding.searchResultTitle.text = item.title
itemBinding.searchResultDetail.text = item.provider.siteName
clickUrl = item.clickUrl
item.provider.logo?.let { imageUrl = it }
}
}
itemBinding.searchItemRoot.setOnClickListener {
clickListener.onClick(clickUrl)
}
getImageFromUrl(imageUrl, itemBinding.searchResultImage)
}
private fun getImageFromUrl(url: String, imageView: ImageView) {
Glide.with(itemBinding.root)
.load(url)
.centerCrop()
.into(imageView);
}
}
}
End
If you would like to learn more about Search Kit and see the Codelab, you can visit the following websites:
https://developer.huawei.com/consum.../HMSCore-Guides/introduction-0000001055591730
https://developer.huawei.com/consumer/en/codelab/HMSSearchKit/index.html#0
Very nice guide.
Amazing.
Thank you very much
It's a very nice example.

Real-time Locating Helps Users Get Around

Real-time locating is a core function for many apps, allowing them to quickly and accurately locate users' real time locations.
HUAWEI Location Kit enables apps to quickly obtain precise user locations and build up global locating capabilities, helping you implement personalized map display and interaction, as well as improve overall location-based service experience.
This article demonstrates how to use HUAWEI Location Kit and Map Kit to implement the real-time locating capability in an app.
Expectations​An app can obtain and display a user's real-time location on the map, especially when the app is launched for the first time. The map display changes in accordance to the user's actual location.
{
"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"
}
Involved Capabilities​Location Kit: basic locating
Map Kit: map display
Implementation Principle​An app uses Location Kit to obtain a user's real-time location and uses Map Kit to display the My Location button on the in-app map that the user can tap to determine their real-time location.
Preparations​Register as a developer and create a project in AppGallery Connect.
Click here to register as a developer.
Create an app, add the SHA-256 signing certificate fingerprint, enable Map Kit and Site Kit, and download the agconnect-services.json file of the app. For detailed instructions, please visit the official website of HUAWEI Developers.
Configure the Android Studio project.
Copy the agconnect-services.json file to the app directory of the project.
Go to allprojects > repositories and configure the Maven repository address for the HMS Core SDK.
Go to buildscript > repositories and configure the Maven repository address for the HMS Core SDK.
If the agconnect-services.json file has been added to the app, go to buildscript > dependencies and add the AppGallery Connect plugin configuration.
Code:
buildscript {
repositories {
maven { url 'https://developer.huawei.com/repo/' }
google()
jcenter()
}
dependencies {
classpath 'com.android.tools.build:gradle:3.3.2'
classpath 'com.huawei.agconnect:agcp:1.3.1.300'
}
}
allprojects {
repositories {
maven { url 'https://developer.huawei.com/repo/' }
google()
jcenter()
}
}
Add build dependencies in the dependencies block.
Code:
dependencies {
implementation 'com.huawei.hms:maps:{version}'
implementation 'com.huawei.hms:location:{version}'
}
Add the following configuration to the file header.
Code:
apply plugin: 'com.huawei.agconnect'
Copy the signing certificate generated in Generating a Signing Certificate to the app directory of your project, and configure the signing certificate in android in the build.gradle file.
Code:
signingConfigs {
release {
// Signing certificate.
storeFile file("**.**")
// KeyStore password.
storePassword "******"
// Key alias.
keyAlias "******"
// Key password.
keyPassword "******"
v2SigningEnabled true
v2SigningEnabled true
}
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
debuggable true
}
debug {
debuggable true
}
}
Key Code Implementation​(1) Compile a service to obtain a user's real-time location.
Java:
public class LocationService extends Service {
private final String TAG = this.getClass().getSimpleName();
List<ILocationChangedLister> locationChangedList = new ArrayList<>();
// Location
private FusedLocationProviderClient fusedLocationProviderClient;
private LocationRequest mLocationRequest;
private final LocationCallback mLocationCallback = new LocationCallback() {
@Override
public void onLocationResult(LocationResult locationResult) {
super.onLocationResult(locationResult);
locationResult.getLocations();
Log.d(TAG, "onLocationResult: " + locationResult);
Location location = locationResult.getLocations().get(0);
Log.w(TAG, "onLocationResult:Latitude " + location.getLatitude());
Log.w(TAG, "onLocationResult:Longitude " + location.getLongitude());
for (ILocationChangedLister locationChanged : locationChangedList) {
locationChanged.locationChanged(new LatLng(location.getLatitude(), location.getLongitude()));
}
}
@Override
public void onLocationAvailability(LocationAvailability locationAvailability) {
super.onLocationAvailability(locationAvailability);
Log.d(TAG, "onLocationAvailability: " + locationAvailability.toString());
}
};
private final MyBinder binder = new MyBinder();
private final Random generator = new Random();
@Nullable
@Override
public IBinder onBind(Intent intent) {
return binder;
}
@Override
public void onCreate() {
Log.i("DemoLog", "TestService -> onCreate, Thread: " + Thread.currentThread().getName());
super.onCreate();
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.i("DemoLog",
"TestService -> onStartCommand, startId: " + startId + ", Thread: " + Thread.currentThread().getName());
return START_NOT_STICKY;
}
@Override
public boolean onUnbind(Intent intent) {
Log.i("DemoLog", "TestService -> onUnbind, from:" + intent.getStringExtra("from"));
return false;
}
@Override
public void onDestroy() {
Log.i("DemoLog", "TestService -> onDestroy, Thread: " + Thread.currentThread().getName());
super.onDestroy();
}
public int getRandomNumber() {
return generator.nextInt();
}
public void addLocationChangedlister(ILocationChangedLister iLocationChangedLister) {
locationChangedList.add(iLocationChangedLister);
}
public void getMyLoction() {
Log.d(TAG, "getMyLoction: ");
fusedLocationProviderClient = LocationServices.getFusedLocationProviderClient(this);
SettingsClient settingsClient = LocationServices.getSettingsClient(this);
LocationSettingsRequest.Builder builder = new LocationSettingsRequest.Builder();
mLocationRequest = new LocationRequest();
builder.addLocationRequest(mLocationRequest);
LocationSettingsRequest locationSettingsRequest = builder.build();
// Location setting
settingsClient.checkLocationSettings(locationSettingsRequest)
.addOnSuccessListener(locationSettingsResponse -> fusedLocationProviderClient
.requestLocationUpdates(mLocationRequest, mLocationCallback, Looper.getMainLooper())
.addOnSuccessListener(aVoid -> Log.d(TAG, "onSuccess: " + aVoid)))
.addOnFailureListener(Throwable::printStackTrace);
}
public class MyBinder extends Binder {
public LocationService getService() {
return LocationService.this;
}
}
public interface ILocationChangedLister {
/**
* Update the location information
*
* @param latLng The new location information
*/
public void locationChanged(LatLng latLng);
}
}
(2) Add a map in the activity to monitor a user's real-time location.
Add a map using the XML layout file:
XML:
<com.huawei.hms.maps.MapView
android:id="@+id/map"
android:layout_width="match_parent"
android:layout_height="match_parent" />
Add a map in the activity:
XML:
mapView.onCreate(null);
mapView.getMapAsync(this);
Tap My Location button to display the current location on the map:
XML:
@Override
public void onMapReady(HuaweiMap huaweiMap) {
hMap = huaweiMap;
hMap.setMyLocationEnabled(true);
}
Bind Location Kit to listen to location changing events:
private ServiceConnection conn = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder binder) {
isBound = true;
if (binder instanceof LocationService.MyBinder) {
LocationService.MyBinder myBinder = (LocationService.MyBinder) binder;
locationService = myBinder.getService();
Log.i(TAG, "ActivityA onServiceConnected");
locationService.addLocationChangedlister(iLocationChangedLister);
locationService.getMyLoction();
}
}
@Override
public void onServiceDisconnected(ComponentName name) {
isBound = false;
locationService = null;
Log.i(TAG, "ActivityA onServiceDisconnected");
}
};
Bind the activity to LocationService:
private void bindLocationService() {
Intent intent = new Intent(mActivity, LocationService.class);
intent.putExtra("from", "ActivityA");
Log.i(TAG, "-------------------------------------------------------------");
Log.i(TAG, "bindService to ActivityA");
mActivity.bindService(intent, conn, Context.BIND_AUTO_CREATE);
}
Process the location changing events in the location changing listener:
LocationService.ILocationChangedLister iLocationChangedLister = new LocationService.ILocationChangedLister() {
@Override
public void locationChanged(LatLng latLng) {
Log.d(TAG, "locationChanged: " + latLng.latitude);
Log.d(TAG, "locationChanged: " + latLng.longitude);
updateLocation(latLng);
}
};
Update map view:
private void updateLocation(LatLng latLng) {
mLatLng = latLng;
hMap.moveCamera(CameraUpdateFactory.newLatLngZoom(latLng, 1));
}
Testing the App​You can use a mock location app to change your current location and see how the map view and My Location button alter accordingly.
To learn more, please visit:
HUAWEI Developers official website
Development Guide
Reddit to join developer discussions
GitHub or Gitee to download the demo and sample code
Stack Overflow to solve integration problems
Follow our official account for the latest HMS Core-related news and updates.
Original Source

Share Educational Training Video Summary on Social Media by Huawei Video Summarization using Huawei HiAI in Android

Introduction
In this article, we will learn how to integrate Huawei Video summarization using Huawei HiAI. We will build the Video preview maker application to share it on social media to increase your video views.
What is Video summarization?
In general Video summarization is the process of distilling a raw video into a more compact form without losing much information.
This Service can generate a 10 seconds, 15 seconds, or 30 seconds video summary of a single video or multiple videos containing the original voice.
Note: Total Video lenght should not exceed more than 10 minutes.
Click to expand...
Click to collapse
Implementing an advanced multi-dimensional scoring framework, the aesthetic engine assists with shooting, photo selection, video editing, and video splitting, by comprehending complex subjective aspects in images, and making high-level judgments related to the attractiveness, memorability and engaging nature of images.
Features
Fast: This algorithm is currently developed based on the deep neural network, to fully utilize the neural processing unit (NPU) of Huawei mobile phones to accelerate the neural network, achieving an acceleration of over 10 times.
Lightweight: This API greatly reduces the computing time and ROM space the algorithm model takes up, making your app more lightweight.
Comprehensive scoring: The aesthetic engine provides scoring to measure image quality from objective dimensions (image quality), subjective dimensions (sensory evaluation), and photographic dimensions (rule evaluation).
Portrait aesthetics scoring: An industry-leading portrait aesthetics scoring feature obtains semantic information about human bodies in the image, including the number of people, individual body builds, positions, postures, facial positions and angles, eye movements, mouth movements, and facial expressions. Aesthetic scores of the portrait are given according to the various types of the body semantic information.
How to integrate Video Summarization
Configure the application on the AGC.
Apply for HiAI Engine Library
Client application development process.
Configure application on the AGC
Follow the steps
Step 1: We need to register as a developer account in AppGallery Connect. If you are already a developer ignore this step.
Step 2: Create an app by referring to Creating a Project and Creating an App in the Project
Step 3: Set the data storage location based on the current location.
Step 4: Generating a Signing Certificate Fingerprint.
Step 5: Configuring the Signing Certificate Fingerprint.
Step 6: Download your agconnect-services.json file, paste it into the app root directory.
Apply for HiAI Engine Library
What is Huawei HiAI?
HiAI is Huawei’s AI computing platform. HUAWEI HiAI is a mobile terminal–oriented artificial intelligence (AI) computing platform that constructs three layers of ecology: service capability openness, application capability openness, and chip capability openness. The three-layer open platform that integrates terminals, chips, and the cloud brings more extraordinary experience for users and developers.
How to apply for HiAI Engine?
Follow the steps
Step 1: Navigate to this URL, choose App Service > Development and click HUAWEI HiAI.
{
"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"
}
Step 2: Click Apply for HUAWEI HiAI kit.
Step 3: Enter required information like Product name and Package name, click Next button.
Step 4: Verify the application details and click Submit button.
Step 5: Click the Download SDK button to open the SDK list.
Step 6: Unzip downloaded SDK and add into your android project under libs folder.
Step 7: Add jar files dependences into app build.gradle file.
Code:
implementation fileTree(include: ['*.aar', '*.jar'], dir: 'libs')
implementation 'com.google.code.gson:gson:2.8.6'
repositories {
flatDir {
dirs 'libs'
}
}
Client application development process
Follow the steps
Step 1: Create an Android application in the Android studio (Any IDE which is your favorite).
Step 2: Add the App level Gradle dependencies. Choose inside project Android > app > build.gradle.
Code:
apply plugin: 'com.android.application'
apply plugin: 'com.huawei.agconnect'
Root level gradle dependencies.
Code:
maven { url 'https://developer.huawei.com/repo/' }
classpath 'com.huawei.agconnect:agcp:1.4.1.300'
Step 3: Add permission in AndroidManifest.xml
Code:
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<!-- CAMERA -->
<uses-permission android:name="android.permission.CAMERA" />
<uses-feature android:name="android.hardware.camera" />
<uses-feature android:name="android.hardware.camera.autofocus" />
Step 4: Build application.
First request run time permission
Code:
private void requestPermissions() {
try {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
int permission = ActivityCompat.checkSelfPermission(this,
Manifest.permission.WRITE_EXTERNAL_STORAGE);
if (permission != PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE,
Manifest.permission.READ_EXTERNAL_STORAGE, Manifest.permission.CAMERA}, 0x0010);
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
Initialize vision base
Code:
private void initVisionBase() {
VisionBase.init(VideoSummaryActivity.this, new ConnectionCallback() {
[USER=439709]@override[/USER]
public void onServiceConnect() {
Log.i(LOG, "onServiceConnect ");
Toast.makeText(VideoSummaryActivity.this, "Service Connected", Toast.LENGTH_SHORT).show();
}
[USER=439709]@override[/USER]
public void onServiceDisconnect() {
Log.i(LOG, "onServiceDisconnect");
Toast.makeText(VideoSummaryActivity.this, "Service Disconnected", Toast.LENGTH_SHORT).show();
}
});
}
Create video Async class
Code:
public class VideoAsyncTask extends AsyncTask<String, Void, String> {
private static final String LOG = VideoAsyncTask.class.getSimpleName();
private Context context;
private VideoCoverListener listener;
private AestheticsScoreDetector aestheticsScoreDetector;
public VideoAsyncTask(Context context, VideoCoverListener listener) {
this.context = context;
this.listener = listener;
}
[USER=439709]@override[/USER]
protected String doInBackground(String... paths) {
Log.i(LOG, "init VisionBase");
VisionBase.init(context, ConnectManager.getInstance().getmConnectionCallback()); //try to start AIEngine
if (!ConnectManager.getInstance().isConnected()) { //wait for AIEngine service
ConnectManager.getInstance().waitConnect();
}
Log.i(LOG, "init videoCover");
aestheticsScoreDetector = new AestheticsScoreDetector(context);
AEModelConfiguration aeModelConfiguration;
aeModelConfiguration = new AEModelConfiguration();
aeModelConfiguration.getSummerizationConf().setSummerizationMaxLen(10);
aeModelConfiguration.getSummerizationConf().setSummerizationMinLen(2);
aestheticsScoreDetector.setAEModelConfiguration(aeModelConfiguration);
String videoResult = null;
if (listener.isAsync()) {
videoCoverAsync(paths);
videoResult = "-10000";
} else {
videoResult = videoCover(paths);
aestheticsScoreDetector.release();
}
//release engine after detect finished
return videoResult;
}
[USER=439709]@override[/USER]
protected void onPostExecute(String resultScore) {
if (!resultScore.equals("-10000")) {
listener.onTaskCompleted(resultScore, false);
}
super.onPostExecute(String.valueOf(resultScore));
}
private String videoCover(String[] videoPaths) {
if (videoPaths == null) {
Log.e(LOG, "uri is null ");
return null;
}
JSONObject jsonObject = new JSONObject();
int position = 0;
Video[] videos = new Video[videoPaths.length];
for (String path : videoPaths) {
Video video = new Video();
video.setPath(path);
videos[position++] = video;
}
jsonObject = aestheticsScoreDetector.getVideoSummerization(videos, null);
if (jsonObject == null) {
Log.e(LOG, "return JSONObject is null");
return "return JSONObject is null";
}
if (!jsonObject.optString("resultCode").equals("0")) {
Log.e(LOG, "return JSONObject resultCode is not 0");
return jsonObject.optString("resultCode");
}
Log.d(LOG, "videoCover get score end");
AEVideoResult aeVideoResult = aestheticsScoreDetector.convertVideoSummaryResult(jsonObject);
if (null == aeVideoResult) {
Log.e(LOG, "aeVideoResult is null ");
return null;
}
String result = new Gson().toJson(aeVideoResult, AEVideoResult.class);
return result;
}
private void videoCoverAsync(String[] videoPaths) {
if (videoPaths == null) {
Log.e(LOG, "uri is null ");
return;
}
Log.d(LOG, "runVisionService " + "start get score");
CVisionCallback callback = new CVisionCallback();
int position = 0;
Video[] videos = new Video[videoPaths.length];
for (String path : videoPaths) {
Video video = new Video();
video.setPath(path);
videos[position++] = video;
}
aestheticsScoreDetector.getVideoSummerization(videos, callback);
}
public class CVisionCallback extends VisionCallback {
[USER=439709]@override[/USER]
public void setRequestID(String requestID) {
super.setRequestID(requestID);
}
[USER=439709]@override[/USER]
public void onDetectedResult(AnnotateResult annotateResult) throws RemoteException {
if (annotateResult != null) {
Log.e("Visioncallback", annotateResult.toString());
}
Log.e("Visioncallback", annotateResult.getResult().toString());
JSONObject jsonObject = null;
try {
jsonObject = new JSONObject(annotateResult.getResult().toString());
} catch (JSONException e) {
e.printStackTrace();
}
if (jsonObject == null) {
Log.e(LOG, "return JSONObject is null");
aestheticsScoreDetector.release();
return;
}
if (!jsonObject.optString("resultCode").equals("0")) {
Log.e(LOG, "return JSONObject resultCode is not 0");
aestheticsScoreDetector.release();
return;
}
AEVideoResult aeVideoResult = aestheticsScoreDetector.convertVideoSummaryResult(jsonObject);
if (aeVideoResult == null) {
aestheticsScoreDetector.release();
return;
}
String result = new Gson().toJson(aeVideoResult, AEVideoResult.class);
aestheticsScoreDetector.release();
listener.onTaskCompleted(result, true);
}
[USER=439709]@override[/USER]
public void onDetectedInfo(InfoResult infoResult) throws RemoteException {
JSONObject jsonObject = null;
try {
jsonObject = new JSONObject(infoResult.getInfoResult().toString());
AEDetectVideoStatus aeDetectVideoStatus = aestheticsScoreDetector.convertDetectVideoStatusResult(jsonObject);
if (aeDetectVideoStatus != null) {
listener.updateProcessProgress(aeDetectVideoStatus);
} else {
Log.d(LOG, "[ASTaskPlus onDetectedInfo]aeDetectVideoStatus result is null!");
}
} catch (JSONException e) {
e.printStackTrace();
}
}
[USER=439709]@override[/USER]
public void onDetectedError(ErrorResult errorResult) throws RemoteException {
Log.e(LOG, errorResult.getResultCode() + "");
aestheticsScoreDetector.release();
listener.onTaskCompleted(String.valueOf(errorResult.getResultCode()), true);
}
[USER=439709]@override[/USER]
public String getRequestID() throws RemoteException {
return null;
}
}
}
Result
Tips and Tricks
Check dependencies added properly
Latest HMS Core APK is required.
Min SDK is 21. Otherwise you will get Manifest merge issue.
If you are taking Video from a camera or gallery make sure your app has camera and storage permission.
Add the downloaded huawei-hiai-vision-ove-10.0.4.307.aar, huawei-hiai-pdk-1.0.0.aar file to libs folder.
Maximum video length is 10 minute.
Resolution should be between 144P and 2160P.
Conclusion
In this article, we have learnt the following concepts.
What is Video summarization?
Features of Video summarization
How to integrate Video summarization using Huawei HiAI
How to Apply Huawei HiAI
How to build the application
Reference
Video summarization
Apply for Huawei HiAI
Happy coding

Categories

Resources