Overview

HUAWEI Wireless Kit is a wireless transmission service that enables apps and mobile devices to perceive each other's network quality of experience (QoE). You can integrate Wireless Kit to improve your app's communication efficiency and bring a smooth app performance for users.

What You Will Learn

In this codelab, you will learn how to:

Hardware Requirements

Software Requirements

Required Knowledge

To integrate Wireless Kit, you must complete the following preparations:

For details, please refer to Preparations for integrating HUAWEI HMS Core.

Adding the AppGallery Connect Configuration File of Your App

  1. Sign in to AppGallery Connect and click My projects.
  2. Find your app project and click the app that needs to integrate the HMS Core SDK.
  3. Go to Project settings > General information. In the App information area, download the agconnect-services.json file.
  4. Copy the agconnect-services.json file to the app directory of your Android Studio project.

Adding SDK Dependencies
1. Open the build.gradle file in the project directory and add the AppGallery Connect plug-in and the Maven repository to it.

buildscript { repositories { ... maven { url https://developer.huawei.com/repo/' } } dependencies { ... classpath 'com.huawei.agconnect:agcp:1.4.1.300' } } allprojects { repositories { ... maven { url https://developer.huawei.com/repo/' } } }

2. Configure the Maven dependency in build.gradle in the app directory.

a) Open the build.gradle file in the app directory.

b) Add the following line under apply plugin: 'com.android.application'.

apply plugin: 'com.huawei.agconnect'

c) Add build dependencies in the dependencies section.

dependencies { implementation 'com.huawei.hms:wireless:{version}' }

Replace {version} with the actual SDK version number. For details, please refer to Version Change History. Example:

implementation 'com.huawei.hms:wireless:5.0.1.305'

3. Configuring Obfuscation Scripts

Before building the APK, configure obfuscation scripts to prevent the HMS Core SDK from being obfuscated.

The obfuscation configuration file is proguard-rules.pro in Android Studio.

1) Open the obfuscation configuration file of your project.

2) Add configurations to exclude the HMS Core SDK from obfuscation.

-ignorewarnings -keepattributes *Annotation* -keepattributes Exceptions -keepattributes InnerClasses -keepattributes Signature -keepattributes SourceFile,LineNumberTable -keep class com.hianalytics.android.**{*;} -keep class com.huawei.updatesdk.**{*;} -keep class com.huawei.hms.**{*;}

3) If you are using AndResGuard, add its trustlist to the obfuscation configuration file.

"R.string.hms*", "R.string.connect_server_fail_prompt_toast", "R.string.getting_message_fail_prompt_toast", "R.string.no_available_network_prompt_toast", "R.string.third_app_*", "R.string.upsdk_*", "R.layout.hms*", "R.layout.upsdk_*", "R.drawable.upsdk*", "R.color.upsdk*", "R.dimen.upsdk*", "R.style.upsdk*", "R.string.agc*"

This section describes how to bind the service corresponding to IQoEService, an Android Interface Definition Language (AIDL) API, to quickly access Wireless Kit for obtaining network QoE feedback.

1. Service binding

Obtain a NetworkQoeClient object. Obtain the intent by calling getNetworkQoeServiceIntent, and bind your app to IQoeService. If the intent fails to be obtained, your app will not be able to use IQoeService.

// Add related Android classes as required. import com.huawei.hmf.tasks.OnFailureListener; import com.huawei.hmf.tasks.OnSuccessListener; import com.huawei.hms.common.ApiException; import com.huawei.hms.wireless.IQoeService; import com.huawei.hms.wireless.NetworkQoeClient; import com.huawei.hms.wireless.WirelessClient; import com.huawei.hms.wireless.WirelessResult; public class NetworkQoeActivity extends AppCompatActivity { private NetworkQoeClient networkQoeClient; private IQoeService qoeService; private ServiceConnection mSrcConn = new ServiceConnection() { @Override public void onServiceConnected(ComponentName name, IBinder service) { qoeService = IQoeService.Stub.asInterface(service); } @Override public void onServiceDisconnected(ComponentName name) { qoeService = null; } }; @Override protected void onCreate(Bundle savedInstanceState) { networkQoeClient = WirelessClient.getNetworkQoeClient(NetworkPredictActivity.this); if (networkQoeClient != null) { networkQoeClient.getNetworkQoeServiceIntent() .addOnSuccessListener(new OnSuccessListener<WirelessResult>() { @Override public void onSuccess(WirelessResult wirelessResult) { Intent intent = wirelessResult.getIntent(); if (intent == null) { return; } NetworkQoeActivity.this.bindService(intent, mSrcConn, Context.BIND_AUTO_CREATE); } }) .addOnFailureListener(new OnFailureListener() { @Override public void onFailure(Exception e) { if (e instanceof ApiException) { ApiException ex = (ApiException) e; int errCode = ex.getStatusCode(); } } }); } } }

2. Callback registration for network QoE information

1) Register the network QoE information callback. The callback includes the parsing of key network QoE data.

// Add related Android classes as required. import com.huawei.hmf.tasks.OnFailureListener; import com.huawei.hmf.tasks.OnSuccessListener; import com.huawei.hms.common.ApiException; import com.huawei.hms.wireless.IQoeCallBack; import com.huawei.hms.wireless.IQoeService; import com.huawei.hms.wireless.NetworkQoeClient; import com.huawei.hms.wireless.WirelessClient; import com.huawei.hms.wireless.WirelessResult; public class NetworkQoeActivity extends AppCompatActivity { private static final String TAG = "networkQoe"; private static final int NETWORK_QOE_INFO_TYPE = 0; private int[] channelIndex = new int[4]; private int[] uLRtt = new int[4]; private int[] dLRtt = new int[4]; private int[] uLBandwidth = new int[4]; private int[] dLBandwidth = new int[4]; private int[] uLRate = new int[4]; private int[] dLRate = new int[4]; private int[] netQoeLevel = new int[4]; private int[] uLPkgLossRate = new int[4]; private IQoeService qoeService; private IQoeCallBack callBack = new IQoeCallBack.Stub() { @Override public void callBack(int type, Bundle qoeInfo) throws RemoteException { if (qoeInfo == null || type != NETWORK_QOE_INFO_TYPE) { Log.e(TAG, "callback failed.type:" + type); return; } int channelNum = 0; if (qoeInfo.containsKey("channelNum")) { channelNum = qoeInfo.getInt("channelNum"); } String channelQoe = String.valueOf(channelNum); for (int i = 0; i < channelNum; i++) { uLRtt[i] = qoeInfo.getInt("uLRtt" + i); dLRtt[i] = qoeInfo.getInt("dLRtt" + i); uLBandwidth[i] = qoeInfo.getInt("uLBandwidth" + i); dLBandwidth[i] = qoeInfo.getInt("dLBandwidth" + i); uLRate[i] = qoeInfo.getInt("uLRate" + i); dLRate[i] = qoeInfo.getInt("dLRate" + i); netQoeLevel[i] = qoeInfo.getInt("netQoeLevel" + i); uLPkgLossRate[i] = qoeInfo.getInt("uLPkgLossRate" + i); channelIndex[i] = qoeInfo.getInt("channelIndex" + i); // channelQoe can be displayed on the user interface via EditText. channelQoe += "," + channelIndex[i] + "," + uLRtt[i] + "," + dLRtt[i] + "," + uLBandwidth[i] + "," + dLBandwidth[i] + "," + uLRate[i] + "," + dLRate[i] + "," + netQoeLevel[i] + "," + uLPkgLossRate[i]; } } }; @Override protected void onCreate(Bundle savedInstanceState) { if (qoeService != null) { try { int ret = qoeService.registerNetQoeCallBack("com.huawei.hms.wirelessdemo",callBack); } catch (RemoteException ex) { // You can add a print task here. } } } }

2) Unregister the network QoE callback. The callback must be the same as that during registration. After unregistration, the callback will not be executed.

public class NetworkQoeActivity extends AppCompatActivity { @Override protected void onCreate(Bundle savedInstanceState) { int ret = 0; if (qoeService != null) { try { ret = qoeService.unRegisterNetQoeCallBack("com.huawei.hms.wirelessdemo", callBack); } catch (RemoteException ex) { // You can add a print task here. } } } }

3) Obtain real-time QoE information.

public class NetworkQoeActivity extends AppCompatActivity { private int[] channelIndex = new int[4]; private int[] uLRtt = new int[4]; private int[] dLRtt = new int[4]; private int[] uLBandwidth = new int[4]; private int[] dLBandwidth = new int[4]; private int[] uLRate = new int[4]; private int[] dLRate = new int[4]; private int[] netQoeLevel = new int[4]; private int[] uLPkgLossRate = new int[4]; private IQoeService qoeService; @Override protected void onCreate(Bundle savedInstanceState) { if (qoeService != null) { try { Bundle qoeInfo = qoeService.queryRealTimeQoe("com.huawei.hms.wirelessdemo"); if (qoeInfo == null) { return; } int channelNum = qoeInfo.getInt("channelNum"); for (int i = 0; i < channelNum; i++) { uLRtt[i] = qoeInfo.getInt("uLRtt" + i); dLRtt[i] = qoeInfo.getInt("dLRtt" + i); uLBandwidth[i] = qoeInfo.getInt("uLBandwidth" + i); dLBandwidth[i] = qoeInfo.getInt("dLBandwidth" + i); uLRate[i] = qoeInfo.getInt("uLRate" + i); dLRate[i] = qoeInfo.getInt("dLRate" + i); netQoeLevel[i] = qoeInfo.getInt("netQoeLevel" + i); uLPkgLossRate[i] = qoeInfo.getInt("uLPkgLossRate" + i); } } catch (RemoteException ex) { // You can add a print task here. } } } }

3. Service unbinding

Use the Android service mechanism, and unbind your app from IQoeService.

NetworkPredictActivity.this.unbindService(mSrcConn); // The mSrvConn parameter must be the same as that of the ServiceConnection object during service binding. It is called in onCreate or onDestroy.

1. Double-click assembleDebug in the Gradle section of Android Studio to run the Android Studio project and generate the APK. Install the APK on the test mobile phone, enable mobile data on the phone, and ensure that the phone can connect to the Internet.

2. Run the APK on the phone.

3. Touch NETWORKQOE to access the Network qoe screen.

1) Touch BIND SERVICE. If Connected is displayed in the TextView, it indicates that the binding is successful.

2) Touch REGISTER CALLBACK. If the value 0 is displayed in the TextView, it indicates that the callback registration is successful. At this time, a string consisting of characters such as numbers, commas, and minus signs will be displayed in the TextView above UNBIND SERVICE. The meanings of the character strings are as follows:

The number before the first comma indicates the number of channels that the phone is connected to. The value 0 indicates that there is no valid channel. The valid value ranges from 1 to 4. A channel group has nine parameters, which refer to the identifier, uplink latency, downlink latency, uplink bandwidth, downlink bandwidth, uplink rate, downlink rate, QoE level, and uplink packet loss rate, respectively. For details about the parameters, see the description in the API Reference.

3) Touch QUERY REAL TIME QOE. In the registered state, the same character string as that during registration will be displayed in the TextView under QUERY REAL TIME QOE. In the unregistered state, 0 will be displayed.

4) Touch UNREGISTER CALLBACK. If the value 0 is displayed in the TextView, it indicates that the callback unregistration is successful. At this time, the value 0 will be displayed in the TextView above UNBIND SERVICE.

5) Touch UNBIND SERVICE, and Disconnected will be displayed in the TextView next to BIND SERVICE.

4. Touch REPORTAPPQUALITY to access the Report app quality screen. This screen will display the data transmission quality of the app.

1eventId**Id is an integer and indicates an exception event of the app. The values are as follows:

2) direction is an integer and indicates the data transmission mode. The values are as follows:

3) netReason is a string and indicates the network result code. The values are as follows:

You can set this parameter to another value for a new problem. If the string consists of integers, the value must be greater than 100.

5. Touch NETWORKPREDICTION to access the Network prediction screen. This screen will display weak signal prediction broadcasts.

1) The first underlined value indicates the predicted time when the mobile device on which your app is running will enter an area with weak signals (enteringTime).
2) The second underlined value indicates the predicted time when the device will leave the area with weak signals (leavingTime).
3) If typeValue is 1, it indicates that the mobile device will enter an area with weak signals after enteringTime has arrived, and will leave the area with weak signals after leavingTime has arrived. If typeValue is 0, it indicates that the previous broadcast is canceled and enteringTime and leavingTime in the current broadcast are ignored.

MainActivity.java

package com.huawei.hms.wirelessdemo; import android.content.Intent; import android.os.Bundle; import android.view.View; import android.widget.Button; import androidx.appcompat.app.AppCompatActivity; /** * Wireless kit test demo * * @since 2020-07-09 */ public class MainActivity extends AppCompatActivity { private Button reportAppQuality; private Button networkPrediction; private Button networkQoe; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); networkQoe = findViewById(R.id.NetworkQoe); // Click the NetworkQoe button to start NetworkQoeActivity. networkQoe.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { Intent intent = new Intent(MainActivity.this, NetworkQoeActivity.class); startActivity(intent); } }); } }

NetworkQoeActivity.java

package com.huawei.hms.wirelessdemo; import android.content.ComponentName; import android.content.Context; import android.content.Intent; import android.content.ServiceConnection; import android.os.Bundle; import android.os.IBinder; import android.os.RemoteException; import android.util.Log; import android.view.View; import android.widget.Button; import android.widget.EditText; import androidx.appcompat.app.AppCompatActivity; import com.huawei.hmf.tasks.OnFailureListener; import com.huawei.hmf.tasks.OnSuccessListener; import com.huawei.hms.common.ApiException; import com.huawei.hms.wireless.IQoeCallBack; import com.huawei.hms.wireless.IQoeService; import com.huawei.hms.wireless.NetworkQoeClient; import com.huawei.hms.wireless.WirelessClient; import com.huawei.hms.wireless.WirelessResult; /** * Network QoE test demo * * @since 2020-07-09 */ public class NetworkQoeActivity extends AppCompatActivity { private static final String TAG = "networkQoe"; private static final int NETWORK_QOE_INFO_TYPE = 0; private Button getQoeButton; private Button registerButton; private Button unRegisterButton; private Button showQoeDetailButton; private Button cancelQoeButton; private EditText getQoeStateText; private EditText registerStateText; private EditText unregisterStateText; private EditText showQoeDetailsText; private EditText callQoeDetails; private int[] channelIndex = new int[4]; private int[] uLRtt = new int[4]; private int[] dLRtt = new int[4]; private int[] uLBandwidth = new int[4]; private int[] dLBandwidth = new int[4]; private int[] uLRate = new int[4]; private int[] dLRate = new int[4]; private int[] netQoeLevel = new int[4]; private int[] uLPkgLossRate = new int[4]; private IQoeService qoeService = null; private ServiceConnection srcConn = new ServiceConnection() { @Override public void onServiceConnected(ComponentName name, IBinder service) { qoeService = IQoeService.Stub.asInterface(service); getQoeStateText.setText("Connected"); } @Override public void onServiceDisconnected(ComponentName name) { qoeService = null; Log.i(TAG, "onServiceDisConnected."); getQoeStateText.setText("Disconnected"); } }; private IQoeCallBack callBack = new IQoeCallBack.Stub() { @Override public void callBack(int type, Bundle qoeInfo) throws RemoteException { if (qoeInfo == null || type != NETWORK_QOE_INFO_TYPE) { Log.e(TAG, "callback failed.type:" + type); return; } int channelNum = 0; if (qoeInfo.containsKey("channelNum")) { channelNum = qoeInfo.getInt("channelNum"); } String channelQoe = String.valueOf(channelNum); for (int i = 0; i < channelNum; i++) { uLRtt[i] = qoeInfo.getInt("uLRtt" + i); dLRtt[i] = qoeInfo.getInt("dLRtt" + i); uLBandwidth[i] = qoeInfo.getInt("uLBandwidth" + i); dLBandwidth[i] = qoeInfo.getInt("dLBandwidth" + i); uLRate[i] = qoeInfo.getInt("uLRate" + i); dLRate[i] = qoeInfo.getInt("dLRate" + i); netQoeLevel[i] = qoeInfo.getInt("netQoeLevel" + i); uLPkgLossRate[i] = qoeInfo.getInt("uLPkgLossRate" + i); channelIndex[i] = qoeInfo.getInt("channelIndex" + i); channelQoe += "," + channelIndex[i] + "," + uLRtt[i] + "," + dLRtt[i] + "," + uLBandwidth[i] + "," + dLBandwidth[i] + "," + uLRate[i] + "," + dLRate[i] + "," + netQoeLevel[i] + "," + uLPkgLossRate[i]; } Log.i(TAG, channelQoe); callQoeDetails.setText(channelQoe); } }; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_network_qoe); this.setTitle("Network qoe"); initWidget(); // Bind with QoeService. bindQoeService(); // Register a network QoE callback. registerButton.setOnClickListener(new View.OnClickListener() { @Override public void onClick (View view) { int ret = 0; if (qoeService != null) { try { ret = qoeService.registerNetQoeCallBack("com.huawei.hms.wirelessdemo", callBack); registerStateText.setText(Integer.toString(ret)); } catch (RemoteException ex) { Log.e(TAG, "no registerNetQoeCallback api"); } } } }); // Unregister the network QoE callback. unRegisterButton.setOnClickListener(new View.OnClickListener() { @Override public void onClick (View view) { int ret = 0; if (qoeService != null) { try { ret = qoeService.unRegisterNetQoeCallBack("com.huawei.hms.wirelessdemo", callBack); unregisterStateText.setText(Integer.toString(ret)); } catch (RemoteException ex) { Log.e(TAG, "no unregisterNetQoeCallback api"); } } } }); // Query real-time QoE information. showRealTimeQoeInfo(); // Unbind from QoeService. cancelQoeButton.setOnClickListener(new View.OnClickListener() { @Override public void onClick (View view) { if (qoeService != null) { NetworkQoeActivity.this.unbindService(srcConn); qoeService = null; getQoeStateText.setText("Disconnected"); } } }); } private void initWidget() { getQoeButton = findViewById(R.id.ConnectQoe); registerButton = findViewById(R.id.registerQoe); unRegisterButton = findViewById(R.id.unRegisterQoe); showQoeDetailButton = findViewById(R.id.getQoeData); cancelQoeButton = findViewById(R.id.cancleService); getQoeStateText = findViewById(R.id.ConnectQoeState); registerStateText = findViewById(R.id.registerState); unregisterStateText = findViewById(R.id.unregisterState); showQoeDetailsText = findViewById(R.id.getQoeDataContext); callQoeDetails = findViewById(R.id.callQoeDetails); } private void bindQoeService() { getQoeButton.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { NetworkQoeClient networkQoeClient = WirelessClient.getNetworkQoeClient(NetworkQoeActivity.this); if (networkQoeClient != null) { networkQoeClient.getNetworkQoeServiceIntent() .addOnSuccessListener(new OnSuccessListener<WirelessResult>() { @Override public void onSuccess(WirelessResult wirelessResult) { Intent intent = wirelessResult.getIntent(); if (intent == null) { Log.i(TAG, "intent is null."); return; } NetworkQoeActivity.this.bindService(intent, srcConn, Context.BIND_AUTO_CREATE); } }) .addOnFailureListener(new OnFailureListener() { @Override public void onFailure(Exception exception) { if (exception instanceof ApiException) { ApiException ex = (ApiException) exception; int errCode = ex.getStatusCode(); Log.e(TAG, "Get intent failed:" + errCode); } } }); } } }); } private void showRealTimeQoeInfo() { showQoeDetailButton.setOnClickListener(new View.OnClickListener() { @Override public void onClick (View view) { if (qoeService != null) { try { Bundle qoeInfo = qoeService.queryRealTimeQoe("com.huawei.hms.wirelessdemo"); if (qoeInfo == null) { Log.e(TAG, "queryRealTimeQoe is empty."); return; } int channelNum = 0; if (qoeInfo.containsKey("channelNum")) { channelNum = qoeInfo.getInt("channelNum"); } String channelQoe = String.valueOf(channelNum); for (int i = 0; i < channelNum; i++) { uLRtt[i] = qoeInfo.getInt("uLRtt" + i); dLRtt[i] = qoeInfo.getInt("dLRtt" + i); uLBandwidth[i] = qoeInfo.getInt("uLBandwidth" + i); dLBandwidth[i] = qoeInfo.getInt("dLBandwidth" + i); uLRate[i] = qoeInfo.getInt("uLRate" + i); dLRate[i] = qoeInfo.getInt("dLRate" + i); netQoeLevel[i] = qoeInfo.getInt("netQoeLevel" + i); uLPkgLossRate[i] = qoeInfo.getInt("uLPkgLossRate" + i); channelIndex[i] = qoeInfo.getInt("channelIndex" + i); channelQoe += "," + channelIndex[i] + "," + uLRtt[i] + "," + dLRtt[i] + "," + uLBandwidth[i] + "," + dLBandwidth[i] + "," + uLRate[i] + "," + dLRate[i] + "," + netQoeLevel[i] + "," + uLPkgLossRate[i]; } Log.i(TAG, channelQoe); showQoeDetailsText.setText(channelQoe); } catch (RemoteException exception) { Log.e(TAG, "no unregisterNetQoeCallback api"); } } } }); } }

Well done. You have successfully completed this codelab and learned how to:

For more information, please click the following links:
Wireless Kit
To download the sample code, please click the button below:

Download

Code copied