Huawei WisePlay DRM Solution
Digital rights management (a.k.a DRM) protects digital media copy rights. The purpose is to prohibit unauthorized redistribution of digital media and restrict the ways that consumers can copy purchased content.
In general, DRM systems have been implemented by embedding code that prevents copying, specifies a time period in which the content can be accessed or limits the number of devices the media can be installed on.
There are several DRM solutions on market, one of the frequently used solution is Widevine DRM provided by Google that is mainly used in Android and Google native devices.
On the other hand, for the purposes of this article, Huawei WisePlay DRM solution will be analyzed. WisePlay DRM provides royalty-free (WisePlay doesn’t charge a license fee in order to implement its protection technology), standards-based digital content copyright protection capabilities , supports both hardware and software level DRM capabilities, and builds high-quality digital content service copyright protection capabilities 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"
}
Key Features of WisePlay DRM
1) Online Playback (VOD/Live TV)
The content license will be deleted when the playback session is closed.
2) Offline Playback(VOD)
The content license will be stored in the device.
3) Hardware and Software Level DRM
WisePlay DRM supports both hardware and software level encryption capabilities.
The difference between hardware-level and software-level encryption capabilities lies in device security level. Most of the service providers requires hardware-level DRM capability for the high quality e.g. 4K video media content for data protection.
The Trusted Application (a.k.a TA) running at the Trusted Execution Environment (a.k.a TEE) layer is required for the hardware-level encryption capability. The TA running at the TEE layer is not required for the software-level encryption capability and encryption depends on device chip capabilities.
According to software-level DRM capability, data encryption and other operations are performed at the Rich Operating System Execution Environment (a.k.a REE) layer. Content security is protected by software.
4) Supports Multiple Content Formats
WisePlay DRM provides most frequently used adaptive streaming content formats:
fMP4 DASH
fMP4 HLS
TS HLS
5) Supports Multiple Encryption Algorithms
WisePlay DRM provides most frequently used adaptive streaming content formats:
CENC
AES128-CTR
AES128-CBC
Development Scenarios
1) Obtain Online License
Call isCryptoSchemeSupported() method to check whether the UUID of WisePlay DRM is supported.
Create a MediaDrm object and transfer the UUID of WisePlay DRM. The UUID indicates the globally unique ID of each DRM type. (Note: Wiseplay DRM UUID = 3d5e6d35–9b9a-41e8-b843-dd3c6e72c42c)
Call the openSession() method of MediaDrm to open a session and obtain sessionId.
Call getKeyRequest() of MediaDrm to obtain the KeyRequest object in the license request body. The input parameters are described as follows:
sessionId: session ID returned by the openSession method.
initData:
If KeyType is set to MediaDrm.KEY_TYPE_STREAMING or MediaDrm.KEY_TYPE_OFFLINE, set initData to the value of psshbox. The value of psshbox can be obtained from a media index file. (The value is obtained from the MPD file for Dash streams and from M3U8 file for HLS streams.)
If keyType is set to MediaDrm.KEY_TYPE_RELEASE, the initData parameter can be left empty.
mimeType: media type, for example, video/mp4 or video/webm. For the license deletion, this parameter can be left empty.
keyType:
To obtain an offline license, set this parameter to MediaDrm.KEY_TYPE_STREAMING.
To obtain an offline license, set this parameter to MediaDrm.KEY_TYPE_OFFLINE.
To delete a license, set this parameter to MediaDrm.KEY_TYPE_RELEASE
optionalParameters: Leave this parameter empty.
Send a license request online to the server in POST mode. Set Content-Type in the request header to application/json and the request body to the data obtained by using the getData method of KeyRequest in the preceding step.
After receiving a response from the server, use the provideKeyResponse() method to transfer the content of the WisePlay DRM Server response transparently transmitted by the server to the underlying plug-in. The input parameter is the byte array of the license data obtained from the server.
Obtain online license
Code:
private void getOnlineLicense() {
if (!MediaDrm.isCryptoSchemeSupported(WISEPLAY_DRM_UUID)) {
showToast("The device does not support Wiseplay DRM.");
return;
}
HttpURLConnection connection = null;
DataOutputStream outputStream = null;
InputStream inputStream = null;
MediaDrm mediaDrm = null;
byte[] sessionID = null;
try {
// Value of pssh box obtained from the movie.
byte[] initData = Base64.decode(PSSH_BOX, Base64.DEFAULT);
// Obtain the value of pssh box of the movie whose UUID is wiseplay drm from the movie.
String mimeType = "video/mp4";
mediaDrm = new MediaDrm(WISEPLAY_DRM_UUID);
sessionID = mediaDrm.openSession();
MediaDrm.KeyRequest keyRequest =
mediaDrm.getKeyRequest(sessionID, initData, mimeType, MediaDrm.KEY_TYPE_STREAMING, null);
byte[] requestData = keyRequest.getData();
String licenseServerUrl = licenseUrl;
URL url = new URL(licenseServerUrl);
connection = (HttpURLConnection) url.openConnection();
connection.setRequestMethod("POST");
connection.setDoOutput(true);
connection.setDoInput(true);
connection.setRequestProperty("content-type", "application/json");
connection.connect();
outputStream = new DataOutputStream(connection.getOutputStream());
outputStream.write(requestData);
int responseCode = connection.getResponseCode();
if (responseCode == HttpURLConnection.HTTP_OK) {
inputStream = connection.getInputStream();
byte[] response = toByteArray(inputStream);
Log.i(TAG, "getOnlineLicense response : " +
new String(response, StandardCharsets.UTF_8));
mediaDrm.provideKeyResponse(sessionID, response);
showToast("get online license success.");
}
} catch (NotProvisionedException | IOException | DeniedByServerException
| ResourceBusyException | UnsupportedSchemeException e) {
e.printStackTrace();
Log.i(TAG, "get online license failed: " + e.getMessage());
} finally {
try {
if (outputStream != null) {
outputStream.close();
}
if (inputStream != null) {
inputStream.close();
}
if (connection != null) {
connection.disconnect();
}
if (mediaDrm != null) {
if (sessionID != null) {
mediaDrm.closeSession(sessionID);
}
mediaDrm.close();
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
2) Obtain Offline License
The process is the same as that in obtain online license.
The difference lies in the input parameter for calling the getKeyRequest API of MediaDrm.
keyType must be set as MediaDrm.KEY_TYPE_OFFLINE
After obtaining an offline license, call the provideKeyResponse() method to query keySetId indicating the unique ID of the offline license. Keep it secure for offline play content.
3) Delete Offline License
The process is the same as that in obtain online license.
The difference lies in the input parameter for calling the getKeyRequest API of MediaDrm.
keyType must be set as MediaDrm.KEY_TYPE_RELEASE
4) Play Content with Offline License
Call restoreKeys() of MediaDrm and pass keySetId. The offline license can be used later for playing the content.
If the license has expired or keySetId does not exist, calling restoreKeys will fail.
If the license has expired, do not initialize the codec.
Code:
private void useOfflineLicense() {
if (!MediaDrm.isCryptoSchemeSupported(WISEPLAY_DRM_UUID)) {
showToast("The device does not support wiseplay drm.");
return;
}
// Obtain the keySetId of the license from the store.
byte[] keySetIdToRestore = offlineKeySetId;
MediaDrm mediaDrm;
byte[] sessionID;
try {
mediaDrm = new MediaDrm(WISEPLAY_DRM_UUID);
sessionID = mediaDrm.openSession();
mediaDrm.restoreKeys(sessionID, keySetIdToRestore);
// If resotreKeys succeed, you can play it with this license.
showToast("use offline license success.");
mediaDrm.closeSession(sessionID);
mediaDrm.close();
} catch (NotProvisionedException | UnsupportedSchemeException | ResourceBusyException e) {
e.printStackTrace();
Log.i(TAG, "use offline license failed: " + e.getMessage());
}
}
Things to Consider
WisePlay DRM now supports Huawei phones with Kirin 990 chipset (EMUI 10.1 or later installed)
WisePlay DRM is available for Enterprise Developers now.
You can find more: How to join Huawei Developer, register an account, integrate your apps to Huawei AppGallery and so on.
Please refer to below link.
APP Development Process
WisePlay DRM Integration Preparation Steps:https://developer.huawei.com/consumer/en/doc/development/HMS-Guides/wiseplay-preparation
Related
Opportunity
We are living in a very-connected and fast-paced world where everything needs to be fast, efficient, and convenient. Almost everyone uses apps to establish an online presence through different social media platforms or to take advantage of the convenience of availing online products and services. As more people go online and use multiple apps, securing user accounts and verifying user identities are becoming an utmost importance, especially in situations like account sign-in and online transactions. With the limitations and vulnerabilities of using passwords for authenticating user identities, there is a need for a secure user authentication that provides a positive user experience.
{
"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"
}
What is HUAWEI FIDO?
HUAWEI Fast Identity Online (FIDO) enables developers to provide their apps with local biometric authentication capability and online identity verification capability to complement password security. HUAWEI FIDO provides online identity verification capability via FIDO2 Client, which is based on the World Wide Web Consortium’s Web Authentication (WebAuthn) specification.
FIDO2 Client supports both roaming and platform authenticators to enable checking user validity during account sign-in and payment. FIDO2 Client enables online identity verification to help HUAWEI FIDO augment your app’s password security and optimize your app’s usage convenience. The smooth app integration of FIDO2 Client will help developers in implementing HUAWEI FIDO in their apps.
How to integrate FIDO2 Client?
The integration of the FIDO2 Client to your app involves 2 processes. One is a registration process and the other is an authentication process. The following procedures will provide a high-level guide in executing the registration and authentication processes.
Kindly remember that the listed processes must be performed before performing the integration of the FIDO2 Client:
1. Configuring App Information in AppGallery Connect
2. Integrating the HMS SDK
3. Configuring Obfuscation Scrips
To execute the registration process:
1. Acquire a challenge value and related policy from the FIDO server.
Code:
byte[] challengeBytes = SecureRandom.getSeed(16);
2. Initiate the Fido2 registration request.
Code:
PublicKeyCredentialCreationOptions.Builder builder = new PublicKeyCredentialCreationOptions.Builder();
builder.setRp(new PublicKeyCredentialRpEntity(rpId, rpId, null))
.setUser(new PublicKeyCredentialUserEntity(user, user.getBytes()))
.setChallenge(challengeBytes)
.setAttestation(AttestationConveyancePreference.DIRECT)
.setAuthenticatorSelection(new AuthenticatorSelectionCriteria(null, null, null))
.setPubKeyCredParams(new ArrayList<PublicKeyCredentialParameters>(
Arrays.asList(
new PublicKeyCredentialParameters(PublicKeyCredentialType.PUBLIC_KEY, Algorithm.ES256),
new PublicKeyCredentialParameters(PublicKeyCredentialType.PUBLIC_KEY, Algorithm.RS256))))
.setTimeoutSeconds(60L);
if (regCredentialId != null) {
builder.setExcludeList(new ArrayList<PublicKeyCredentialDescriptor>(
Arrays.asList(new PublicKeyCredentialDescriptor(PublicKeyCredentialType.PUBLIC_KEY, regCredentialId))));
3. Initiate the registration by calling Fido2Client.getRegistrationIntent() to obtain a Fido2Intent instance and start the FIDO client registration process.
Code:
fido2Client.getRegistrationIntent(request, NativeFido2RegistrationOptions.DEFAULT_OPTIONS,
new Fido2IntentCallback() {
@Override
public void onSuccess(Fido2Intent fido2Intent) {
fido2Intent.launchFido2Activity(Fido2DemoActivity.this, Fido2Client.REGISTRATION_REQUEST);
}
@Override
public void onFailure(int errorCode, CharSequence errString) {
showError("Registration failed." + errorCode + "=" + errString);
}
});
The registration starts by calling Fido2Intent.launchFido2Activity() in the callback using Fido2Client.REGISTRATION_REQUEST as requestCode.
4. Receive the registration result by calling Fido2Client.getFido2RegistrationResponse() in the callback Activity.onActivityResult()
Code:
Fido2RegistrationResponse fido2RegistrationResponse = fido2Client.getFido2RegistrationResponse(data);
if (fido2RegistrationResponse.isSuccess()) {
reusltView.append("Registration\n");
reusltView.append(fido2RegistrationResponse.getAuthenticatorAttestationResponse().toJson());
reusltView.append("\n");
regCredentialId = fido2RegistrationResponse.getAuthenticatorAttestationResponse().getCredentialId();
showMsg("Registration successful.");
} else {
showError("Registration failed.", fido2RegistrationResponse);
}
5. Send the registration result to the FIDO Server for verification.
To execute the authentication process:
1. Acquire a challenge value and related policy from the FIDO server.
Code:
byte[] challengeBytes = SecureRandom.getSeed(16);
2. Initiate the Fido2 Authentication request.
Code:
List<PublicKeyCredentialDescriptor> allowList = new ArrayList<>();
allowList.add(new PublicKeyCredentialDescriptor(PublicKeyCredentialType.PUBLIC_KEY, regCredentialId));
PublicKeyCredentialRequestOptions.Builder builder = new PublicKeyCredentialRequestOptions.Builder();
builder.setRpId(rpId).setChallenge(challengeBytes).setAllowList(allowList).setTimeoutSeconds(60L);
return new Fido2AuthenticationRequest(builder.build(), null);
3. Initiate the authentication by calling Fido2Client.getAuthenticationIntent() to obtain the Fido2Intent instance and start the FIDO Client authentication process.
Code:
fido2Client.getAuthenticationIntent(request, NativeFido2AuthenticationOptions.DEFAULT_OPTIONS,
new Fido2IntentCallback() {
@Override
public void onSuccess(Fido2Intent fido2Intent) {
fido2Intent.launchFido2Activity(Fido2DemoActivity.this, Fido2Client.AUTHENTICATION_REQUEST);
}
@Override
public void onFailure(int errorCode, CharSequence errString) {
showError("Authentication failed." + errorCode + "=" + errString);
}
});
The authentication starts by calling Fido2Intent.launchFido2Activity() in the callback using Fido2Client.AUTHENTICATION_REQUEST as requestCode.
4. Receive the authentication response by calling Fido2Client.getFido2AuthenticationResponse() in the callback Activity.onActivityResult().
Code:
Fido2AuthenticationResponse fido2AuthenticationResponse =
fido2Client.getFido2AuthenticationResponse(data);
if (fido2AuthenticationResponse.isSuccess()) {
reusltView.append("Authentication\n");
reusltView.append(fido2AuthenticationResponse.getAuthenticatorAssertionResponse().toJson());
reusltView.append("\n");
showMsg("Authentication successful.");
} else {
showError("Authentication failed.", fido2AuthenticationResponse);
}
5. Send the authentication result to the FIDO server for verification.
The Benefits
To the developers
Provides developers with a high-level guide on integrating the FIDO2 Client so that they could easily implement HUAWEI FIDO to increase the security of their apps.
Related Links
Thanks to Ibrahim Recep Serpici for this article.
More information like this, you can visit HUAWEI Developer Forum
In this article we’re going to take a look at the Huawei Health Kit features so we can easily put these features to our apps.
Health app industry have shown an important increase in recent years.The software and healthcare industry are working together to find the latest technology products for the needs of patients and families.Huawei offers high technology service for the health and fitness app ecosystem with HealthKit and HiHealth Kit service. Huawei and third-party partner capabilities track and customize all aspects of better living.
Data storage : Provides a platform for users to store their fitness and health data.
Data openness : Provides a wide range of APIs for writing and reading speed, positioning, blood sugar level, and other data.
Data interaction : Enables you and your users to agree on data access, guaranteeing proper use and security of personal data.
HiHealth:
https://developer.huawei.com/consumer/en/hms/huawei-healthkit
HealthKit:
https://developer.huawei.com/consumer/en/hms/huawei-healthkit
We will examine the differences between HealthKit and HiHealth in our next articles.I created a sample app which I’ve open-sourced on GitHub for enthusiasts who want to use this service.
https://github.com/tualdev/hms-health-kit-demo
Setting up the Health Kit
You’ll need to do setup before you can use the Health Kit.You can follow the official documentation on how to prepare app and enable Health Kit on App Gallery Connect.
Also you can follow this blog post to integrate your apps with Huawei HMS Core:
https://medium.com/huawei-developers/android-integrating-your-apps-with-huawei-hms-core-1f1e2a090e98
I’ll show you how to implement Sensors Controller features in this article for your android projects.Let’s get started!
Add the required dependencies to the build.gradle file under app folder.We need some dependencies.
Code:
implementation 'com.huawei.hms:hwid:4.0.1.300'
implementation 'com.huawei.agconnect:agconnect-core:1.3.1.300'
implementation 'com.huawei.hms:hihealth-base:5.0.0.300'
Add the required permissions to the AndroidManifest.xml file under app/src/main folder.
Code:
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
<uses-permission android:name="android.permission.BLUETOOTH" />
You need to give some permissions after applying for HealthKit in service cards area.The applied permissions will be displayed on the user authorization page.
{
"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"
}
Let’s continue by coding Sensors Controller functionalities in our project.
Sensors Controller
We can achieve success in the two different scenarios with the sensor controller.The first of these scenarios is to be able to access the built-in sensor that the phone contains like pedometer.You can directly call the register method of SensorsController to register a listener to obtain the data reported by the built-in sensor.
NOTE : Currently, Health Kit does not support the access of devices. If you request the access of fitness and health devices to help users collect data, use HiHealth Kit (for the integration of the HUAWEI Health app) instead.
HiHealth Kit is also applicable if you would like to obtain the fitness and health data collected by Huawei wearables or Huawei ecosystem partners for your services offered to customers.
Using the Built-in Sensor Data of the Phone
Let’s give an example about that how to obtain the incremental step count from a phone.
Firstly, we need to sign in to your HUAWEI ID and obtain the SensorsController object.
Code:
val options = HiHealthOptions.builder().build()
// Sign in to the HUAWEI ID.
val signInHuaweiId = HuaweiIdAuthManager.getExtendedAuthResult(options)
// Obtain the SensorsController
sensorsController = HuaweiHiHealth.getSensorsController(this, signInHuaweiId)
After that, we will register a listener to listen to the step count.To register a listener for receiving raw data reported by a specified data collector, use the SensorsController.register method.
Code:
private val onSamplePointListener =
OnSamplePointListener { samplePoint ->
showSamplePoint(samplePoint)
}
val builder = SensorOptions.Builder()
builder.setDataType(DataType.DT_CONTINUOUS_STEPS_TOTAL)
sensorsController!!.register(builder.build(), onSamplePointListener)
.addOnSuccessListener {
Toast.makeText(this, "registerSteps successed... ", Toast.LENGTH_SHORT).show()
}
.addOnFailureListener {
Toast.makeText(this, "registerSteps failed... ", Toast.LENGTH_SHORT).show()
}
When we no longer need step data, we can use the SensorsController.unregister method to unregister the listener.
Code:
sensorsController!!.unregister(onSamplePointListener).addOnSuccessListener {
Toast.makeText(this, "unregisterSteps successed ...", Toast.LENGTH_SHORT).show()
}.addOnFailureListener { e ->
Toast.makeText(this, "unregisterSteps failed ...", Toast.LENGTH_SHORT).show()
}
Using an External Bluetooth Device
In the second scenario, we will examine how data can be obtained from external bluetooth devices.Note that : Health Kit currently supports only standard Bluetooth BLE heart rate device.
Currently, Health Kit does not support reading data generated by Huawei wearables and the HUAWEI Health app. It is scheduled that the HUAWEI Health app data, including step count, sleep data, workout records, heart rate, and body fat, will be opened up in the future.
Let’s give an example about that how to obtain the heart rate data from the Bluetooth device.
Firstly, we need to sign in to your HUAWEI ID and obtain the BleController and SensorsController objects.
Code:
val options = HiHealthOptions.builder().build()
val signInHuaweiId = HuaweiIdAuthManager.getExtendedAuthResult(options)
sensorsController = HuaweiHiHealth.getSensorsController(this, signInHuaweiId)
bleController = HuaweiHiHealth.getBleController(this, signInHuaweiId)
After that, we need to create a bluetooth scanning callback object by using BleScanCallback.BLE devices detected during the scanning will automatically be called back to the bleDeviceInfo object.
Code:
private val mBleCallback: BleScanCallback = object : BleScanCallback() {
override fun onDeviceDiscover(bleDeviceInfo: BleDeviceInfo) {
// Bluetooth devices detected during the scanning will be called back to the bleDeviceInfo object
Toast.makeText([email protected], "onDeviceDiscover : " + bleDeviceInfo.deviceName, Toast.LENGTH_SHORT).show()
// Save the scanned heart rate devices to the variables for later use.
[email protected] = bleDeviceInfo
}
override fun onScanEnd() {
Toast.makeText([email protected], "onScanEnd Scan called", Toast.LENGTH_SHORT).show()
}
}
For now, we can start scan for available BLE devices.We need to use the BleController.beginScan method to scan for nearby BLE devices.
Code:
bleController!!.beginScan(listOf(DataType.DT_INSTANTANEOUS_HEART_RATE), 15, mBleCallback)
We can stop scanning for Bluetooth devices.We need to use the BleController.endScan method to stop scanning.
Code:
bleController!!.endScan(mBleCallback)
We can save the device to be used by SensorsController.We need to use the BleController.saveDevice method to save the device.After successfully saving the device, you can obtain the data collector objects of the device via SensorsController, for example, using the SensorsController.getDataCollectors method.
Code:
bleController!!.saveDevice(bleDeviceInfo).addOnSuccessListener {
Toast.makeText(this, "saveHeartRateDevice successed... ", Toast.LENGTH_SHORT).show()
}.addOnFailureListener {
Toast.makeText(this, "saveHeartRateDevice failed... ", Toast.LENGTH_SHORT).show()
}
We can delete a device if a BLE device is no longer used.We need to use the BleController.deleteDevice method to delete it.
Code:
bleController!!.deleteDevice(bleDeviceInfo).addOnSuccessListener {
Toast.makeText(this, "removeHeartRateDevice successed... ", Toast.LENGTH_SHORT).show()
}.addOnFailureListener {
Toast.makeText(this, "removeHeartRateDevice failed... ", Toast.LENGTH_SHORT).show()
}
We can also list all external BLE devices that have been saved.
Code:
val bleDeviceInfoTask = bleController!!.savedDevices
bleDeviceInfoTask.addOnSuccessListener { bleDeviceInfos -> // bleDeviceInfos contains the list of the saved devices.
for (bleDeviceInfo in bleDeviceInfos) {
Toast.makeText(this, "Matched BLE devices:" + bleDeviceInfo.deviceName, Toast.LENGTH_SHORT).show()
}
}
We can obtain data collectors of the device.We need to use the SensorsController.getDataCollectors method to obtain all saved data collectors.
Code:
val dataCollectorsOptions = DataCollectorsOptions.Builder().setDataTypes(DataType.DT_INSTANTANEOUS_HEART_RATE).build()
sensorsController!!.getDataCollectors(dataCollectorsOptions)
.addOnSuccessListener { dataCollectors ->
// dataCollectors contains the returned available data collectors.
for (dataCollector in dataCollectors) {
Toast.makeText(this, "Available data collector:" + dataCollector.dataCollectorName, Toast.LENGTH_SHORT).show()
// Save the heart rate data collectors for later use when registering the listener.
[email protected] = dataCollector
}
}
.addOnFailureListener {
Toast.makeText(this, "findDataCollectors failed... ", Toast.LENGTH_SHORT).show()
}
We must use the SensorsController.register method to register a listener for receiving raw data reported by a specified data collector.We will create a listener object for heart rate data. The received heart rate data will be called back to onSamplePoint.
Code:
sensorsController!!.register(
SensorOptions.Builder()
.setDataType(DataType.DT_INSTANTANEOUS_HEART_RATE)
.setDataCollector(dataCollector)
.setCollectionRate(1, TimeUnit.SECONDS)
.build(),
heartrateListener
).addOnSuccessListener(OnSuccessListener<Void?> {
Toast.makeText(this, "registerHeartRate successed... ", Toast.LENGTH_SHORT).show()
}).addOnFailureListener(OnFailureListener {
Toast.makeText(this, "registerHeartRate failed... ", Toast.LENGTH_SHORT).show()
})
private val heartrateListener = OnSamplePointListener { samplePoint ->
Toast.makeText(this, "Heart rate received " + samplePoint.getFieldValue(Field.FIELD_BPM), Toast.LENGTH_SHORT).show()
}
If we do not need to receive real-time data, we can unregister a listener.We need to use the SensorsController.unregister method to unregister the listener.
Code:
sensorsController!!.unregister(heartrateListener).addOnSuccessListener {
Toast.makeText(this, "unregisterHeartRate successed... ", Toast.LENGTH_SHORT).show()
}.addOnFailureListener {
Toast.makeText(this, "unregisterHeartRate failed... ", Toast.LENGTH_SHORT).show()
}
References:
https://developer.huawei.com/consumer/en/doc/development/HMSCore-Guides/service-introduction-0000001050071661
https://forums.developer.huawei.com/forumPortal/en/home
Well explained, can we connect to Non-Huawei devices?
Introduction
To help understand the image content, the scene detection service can classify the scenario content of images and add labels, such as outdoor scenery, indoor places, and buildings.You can create more customised experiences for users based on the data detected from image. Currently Huawei supports detection of 102 scenarios. For details about the scenarios, refer to List of Scenario Identification Categories.
This service can be used to identify image sets by scenario and create intelligent album sets. You can also select various camera parameters based on the scene in your app, to help users to take better-looking photos.
Prerequisite
The scene detection service supports integration with Android 6.0 and later versions.
The scene detection needs READ_EXTERNAL_STORAGE and CAMERA in AndroidManifest.xml.
Implementation of dynamic permission for camera and storage is not covered in this article. Please make sure to integrate dynamic permission feature.
Development
1. Register as a developer account in AppGallery Connect.
2. Create an application and enable ML kit from AppGallery connect.
3. Refer to Service Enabling. Integrate AppGallery connect SDK. Refer to AppGallery Connect Service Getting Started.
4. Add Huawei Scene detection dependencies in app-level build.gradle.
Code:
// ML Scene Detection SDK
implementation 'com.huawei.hms:ml-computer-vision-scenedetection:2.0.3.300'
// Import the scene detection model package.
implementation 'com.huawei.hms:ml-computer-vision-scenedetection-model:2.0.3.300'
implementation 'com.huawei.hms:ml-computer-vision-cloud:2.0.3.300'
5. Sync the gradle.
We have an Activity (MainActivity.java) which has floating buttons to select static scene detection and live scene detection.
Static scene detection is used to detect scene in static images. When we select a photo, the scene detection service returns the results.
Camera stream (Live) scene detection can process camera streams, convert video frames into an MLFrame object, and detect scenarios using the static image detection method.
Implementation of Static scene detection
Code:
private void sceneDetectionEvaluation(Bitmap bitmap) {
//Create a scene detection analyzer instance based on the customized configuration.
MLSceneDetectionAnalyzerSetting setting = new MLSceneDetectionAnalyzerSetting.Factory()
// Set confidence for scene detection.
.setConfidence(confidence)
.create();
analyzer = MLSceneDetectionAnalyzerFactory.getInstance().getSceneDetectionAnalyzer(setting);
MLFrame frame = new MLFrame.Creator().setBitmap(bitmap).create();
Task<List<MLSceneDetection>> task = analyzer.asyncAnalyseFrame(frame);
task.addOnSuccessListener(new OnSuccessListener<List<MLSceneDetection>>() {
public void onSuccess(List<MLSceneDetection> result) {
// Processing logic for scene detection success.
for( MLSceneDetection sceneDetection : result) {
sb.append("Detected Scene : " + sceneDetection.getResult() + " , " + "Confidence : " + sceneDetection.getConfidence() + "\n");
tvResult.setText(sb.toString());
if (analyzer != null) {
analyzer.stop();
}
}
}})
.addOnFailureListener(new OnFailureListener() {
public void onFailure(Exception e) {
// Processing logic for scene detection failure.
// failure.
if (e instanceof MLException) {
MLException mlException = (MLException)e;
// Obtain the result code. You can process the result code and customize respective messages displayed to users.
int errorCode = mlException.getErrCode();
// Obtain the error information. You can quickly locate the fault based on the result code.
String errorMessage = mlException.getMessage();
Log.e(TAG, "MLException : " + errorMessage +", error code: "+ String.valueOf(errorCode));
} else {
// Other errors.
Log.e(TAG, "Exception : " + e.getMessage());
}
if (analyzer != null) {
analyzer.stop();
}
}
});
}
@Override
protected void onDestroy() {
super.onDestroy();
if(analyzer != null) {
analyzer.stop();
}
}
We can set the settings MLSceneDetectionAnalyzerSetting() and set the confidence level for scene detection. setConfidence() methods needs to get float value. After settings are fixed, we can create the analyzer with settings value. Then, we can set the frame with bitmap. Lastly, we have created a task for list of MLSceneDetection object. We have listener functions for success and failure. The service returns list of results. The results have two parameter which are result and confidence. We can set the response to textView tvResult.
{
"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"
}
More details, you can visit https://forums.developer.huawei.com/forumPortal/en/topic/0204400184662360088
we will get accuracy result ?
Overview
QUIC (Quick UDP Internet Connections) is a general-purpose transport layer network protocol.
QUIC is a new transport which reduces latency compared to that of TCP. On the surface, QUIC is very similar to TCP+TLS+HTTP/2 implemented on UDP. Because TCP is implemented in operating system kernels, and middlebox firmware, making significant changes to TCP is next to impossible.
QUIC reduces round trips by working with UDP. With great features like eliminating head of line blocking, loss recovery over UDP by using multiplexed connections and congestion control, the protocol has evolved and is being widely used.
Introduction of hQUIC
hQUIC provides the ability to fulfil our needs for lower packet loss in our applications, high performance in our network operations and reliable fast connection. It supports the gQUIC protocol and provides intelligent congestion control algorithms to avoid congestions in different network environments.
Advantages
Ease of use: Streamlines APIs and shields low-level network details.
High compatibility: Supports gQUIC and Cronet.
Better experience: Outperforms other protocols in poor network conditions
{
"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"
}
What is Cronet?
Cronet is the networking stack of Chromium put into a library for use on mobile. This is the same networking stack that is used in the Chrome browser by over a billion people. It offers an easy-to-use, high performance, standards-compliant, and secure way to perform HTTP requests.
Cronet is a very well implemented and tested network stack that provides almost everything that a standard app needs from a network layer library, things like DNS, Cookies, SSL/TLS, HTTP(S), HTTP2, Proxy/PAC, OSCP, Web sockets, and F̶T̶P̶(soon to be removed). It also supports HTTP over QUIC, soon to be called HTTP3. This makes it a very attractive library to use as the network layer for your mobile app.
How TCP Works?
TCP allows for transmission of information in both directions. This means that computer systems that communicate over TCP can send and receive data at the same time, similar to a telephone conversation. The protocol uses segments (packets) as the basic units of data transmission.
The actual process for establishing a connection with the TCP protocol is as follows:
1. First, the requesting sender sends the server a SYN packet or segment (SYN stands for synchronize) with a unique, random number. This number ensures full transmission in the correct order (without duplicates).
2. If the receiver has received the segment, it agrees to the connection by returning a SYN-ACK packet (ACK stands for acknowledgement) including the client's sequence number plus 1. It also transmits its own sequence number to the client.
3. Finally, the sender acknowledges the receipt of the SYN-ACK segment by sending its own ACK packet, which in this case contains the receiver's sequence number plus 1. At the same time, the client can already begin transferring data to the receiver.
Prerequisite
1. A computer with Android Studio installed and able to access the Internet
2. A Huawei phone with HMS Core (APK) 5.0.0 or later installed for debugging the app
3. Java JDK (1.7 or later)
4. Android API (level 19 or higher)
5. EMUI 3.0 or later
6. HMS Core (APK) 5.0.0 or later
Integration process
1. Open the build.gradle file in the root directory of your Android Studio project.
Code:
buildscript {
buildscript {
repositories {
maven { url 'https://developer.huawei.com/repo/' }
google()
...
}
dependencies {
classpath 'com.android.tools.build:gradle:3.3.2'
}
}
}
2. Open the build.gradle file in the app directory and add dependency on the SDK.
Code:
dependencies {
implementation 'com.huawei.hms:hquic-provider:5.0.0.300'
}
3. Initialise the service
Code:
HQUICManager.asyncInit(context, new HQUICManager.HQUICInitCallback() {
@Override
public void onSuccess() {
Log.i(TAG, "HQUICManager asyncInit success");
}
@Override
public void onFail(Exception e) {
Log.w(TAG, "HQUICManager asyncInit fail");
}
});
4. Initialise the Cronet Engine
Code:
CronetEngine.Builder builder = new CronetEngine.Builder(context);
builder.enableQuic(true);
builder.addQuicHint(getHost(url), DEFAULT_PORT, DEFAULT_ALTERNATEPORT);
cronetEngine = builder.build();
App Development
I will use APIs of the hQUIC SDK by developing a Speed Test app step by step.
I have created HQUICSericeProvider class in which I will create the service using hQuic APIs.
Let us implements the asynchronous initialization API.
Code:
public class HQUICServiceProvider {
private static final String TAG = "HQUICServiceProvider";
private static final int DEFAULT_PORT = 443;
private static final int DEFAULT_ALTERNATEPORT = 443;
private static Executor executor = Executors.newSingleThreadExecutor();
private static CronetEngine cronetEngine;
private Context context;
private UrlRequest.Callback callback;
public HQUICServiceProvider(Context context) {
this.context = context;
init();
}
public void init() {
HQUICManager.asyncInit(
context,
new HQUICManager.HQUICInitCallback() {
@Override
public void onSuccess() {
Log.i(TAG, "HQUICManager asyncInit success");
}
@Override
public void onFail(Exception e) {
Log.w(TAG, "HQUICManager asyncInit fail");
}
});
}
private CronetEngine createCronetEngine(String url) {
if (cronetEngine != null) {
return cronetEngine;
}
CronetEngine.Builder builder = new CronetEngine.Builder(context);
builder.enableQuic(true);
builder.addQuicHint(getHost(url), DEFAULT_PORT, DEFAULT_ALTERNATEPORT);
cronetEngine = builder.build();
return cronetEngine;
}
private UrlRequest buildRequest(String url, String method) {
CronetEngine cronetEngine = createCronetEngine(url);
UrlRequest.Builder requestBuilder =
cronetEngine.newUrlRequestBuilder(url, callback, executor).setHttpMethod(method);
UrlRequest request = requestBuilder.build();
return request;
}
public void sendRequest(String url, String method) {
Log.i(TAG, "callURL: url is " + url + "and method is " + method);
UrlRequest urlRequest = buildRequest(url, method);
if (null != urlRequest) {
urlRequest.start();
}
}
private String getHost(String url) {
String host = null;
try {
java.net.URL url1 = new java.net.URL(url);
host = url1.getHost();
} catch (MalformedURLException e) {
Log.e(TAG, "getHost: ", e);
}
return host;
}
public void setCallback(UrlRequest.Callback mCallback) {
callback = mCallback;
}
}
More details, you can visit https://forums.developer.huawei.com/forumPortal/en/topic/0203400466275620106
It will support only network call related information?
{
"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"
}
AppGalleryKit App and AppGalleryKit Game services allows to jointly operate the apps with Huawei and share revenue generated in the process. Developer will have access to Huawei’s diverse services including HUAWEI AppGallery connection, data reports, activity operations, and user operations to obtain more premium HUAWEI AppGallery resources in order to promotion purposes.
To enable AppGalleryKit App or AppGalleryKitGame operations, you need to sign the HUAWEI AppGallery Connect Distribution Service Agreement For Paid Apps with Huawei. For details about the joint operations process, please refer to Joint Operations Services at a Glance.
AppGalleryKit App and AppGalleryKit Game is a product concept derived from Account, Analytics, In-App Purchases and other kits. With AppGalleryKit App or AppGalleryKit Game, initializing the app, updating the app, implementing Account Kit is optional. But it is necessary to implementing In-App Purchases kit to use AppGalleryKit App or AppGalleryKit Game. Also it is advised that use Analytics Kit, Auth Service, Crash Service, A/B Testing and APM.
AppGalleryKitApp or AppGalleryKitGame is not pure kit integration. It is required for developers to sign AppGalleryKitApp or AppGalleryKitGame related agreements and they are derived from many features.
Initiliazing app, updating the app, Account Kit and In-App Purchases can be implemented seperately. These kits do not depend on AppGalleryKitApp or AppGalleryKitGame. But AppGalleryKitApp or AppGalleryKitGame depends on these kits.
Although we are not going to use AppGalleryKitApp or AppGalleryKit game, we can still use the update status of the application. In this article, we will check if there is an update in a demo app. Of course due to this app will not be in AppGallery market, there will not any update required.
In order to use this feature, first HMS Core is needed to be integrated to the project.
You can click this link to integrate HMS Core to your project.
Adding Dependency
After HMS Core is integrated, app-service library needs to be implemented.
Code:
implementation 'com.huawei.hms:appservice:{version}' // Currently version is 5.0.4.302
We will create a checkUpdate method and use it in onCreate. JosApps.getAppUpdateClient method, AppUpdateClient instance will be obtained. This object provides the methods related to app update. checkAppUpdate method, checks for app updates after the app is launched and initialized.
Java:
private void checkUpdate(){
AppUpdateClient client = JosApps.getAppUpdateClient(this);
client.checkAppUpdate(this, new UpdateCallBack(this));
}
We need to create a static class which is UpdateCallBack and it will implement CheckUpdateCallBack. CheckUpdateCallBack returns a result for checking for app updates. It requires onUpdateInfo, onMarketInstallInfo, onMarketStoreError and onUpdateStoreError methods are implemented.
in onUpdateInfo method, we can get status code, fail code, fail reason and other informations.
For more information you can click this link.
Code:
private static class UpdateCallBack implements CheckUpdateCallBack {
private final WeakReference<MainActivity> weakMainActivity;
private UpdateCallBack(MainActivity mainActivity) {
this.weakMainActivity = new WeakReference<>(mainActivity);
}
public void onUpdateInfo(Intent intent) {
if (intent != null) {
MainActivity mainActivity = null;
if (weakMainActivity.get() != null){
mainActivity = weakMainActivity.get();
}
int status = intent.getIntExtra(UpdateKey.STATUS, 100);
int rtnCode = intent.getIntExtra(UpdateKey.FAIL_CODE, 200);
String rtnMessage = intent.getStringExtra(UpdateKey.FAIL_REASON);
Serializable info = intent.getSerializableExtra(UpdateKey.INFO);
if (info instanceof ApkUpgradeInfo && mainActivity != null ) {
AppUpdateClient client = JosApps.getAppUpdateClient(mainActivity);
//Force Update option is selected as false.
client.showUpdateDialog(mainActivity, (ApkUpgradeInfo) info, false);
Log.i("AppGalleryKit", "checkUpdatePop success");
}
if(mainActivity != null) {
//status --> 3: constant value NO_UPGRADE_INFO, indicating that no update is available.
Log.i("AppGalleryKit","onUpdateInfo status: " + status + ", rtnCode: "
+ rtnCode + ", rtnMessage: " + rtnMessage);
}
}
}
@Override
public void onMarketInstallInfo(Intent intent) {
//onMarketInstallInfo
}
@Override
public void onMarketStoreError(int i) {
//onMarketStoreError
}
@Override
public void onUpdateStoreError(int i) {
//onUpdateStoreError
}
}
In this example, due to we do not have the application released in the market, we got a status code which is equal to 3. This indicates that for the application there is no upgrade needed.
For all status codes, you can check the below image.
For more details, you can check AppGalleryKit App and AppGalleryKit Game development guide links in reference section. Also you can download this demo application from the Github link.
Reference
AppGalleryKit App
AppGalleryKit Game
Github