Overview

The DeviceVirtualization Kit (DV Kit for short) is a multi-device virtualization platform provided by Huawei to facilitate the virtualization of external devices and components. Through this platform, peripheral devices or device components are converted into virtual components of mobile phones, and their capabilities are incorporated and utilized by mobile phones as general capabilities. In addition, capabilities of multiple virtual devices can be used synchronously.

By integrating the DV Kit, developers can use external devices and components in an optimally convenient manner, including but not limited to cameras, speakers, monitors, microphones, wearables, and other peripheral devices. The devices and components can be controlled and switched flexibly, fully utilizing all available resource advantages, to create mutually reinforcing device collaborations that benefit users immensely.

What You Will Create

In this codelab, you will create a demo project, integrate the HUAWEI DeviceVirtualization Kit SDK into the demo project, and complete the overall process setup of the HUAWEI DeviceVirtualization Kit service.

What You Will Learn

Hardware Requirements

Software Requirements

Required Knowledge

HUAWEI DeviceVirtualization Kit integration requires the following preparations:

For details, see DeviceVirtualization Kit Development Preparations.

1. Integrate DeviceVirtualization Kit.

Integrate DeviceVirtualization Kit by following the instructions provided in step 6 in DeviceVirtualization Kit Development Preparations.

2. Add app ID.

Add the app ID generated when creating the app on HUAWEI Developer to the AndroidManifest.xml file of the app. The name icom.huawei.hms.client.appidid, and the value is appid=******. Replace ****** with the ID of your app. For details about how to apply for the access permission of the DeviceVirtualization Kit, see step 4 "Applying for Permission" in the DeviceVirtualization Kit Development Preparations. Note that the access is allowed only after the permission application is approved. Otherwise, an exception will be thrown when the service is connected, and ERROR_CODE_NO_PERMISSION will be returned when the DV Kit API is called.

<meta-data android:name="com.huawei.hms.client.appid" android:value="appid=xxxxxxxxx"/>

3. Perform compatibility check.

MainActivity.java

// Define CURRENT_KIT_VERSION based on the version of the currently integrated DV Kit. static final String CURRENT_KIT_VERSION = "1.0.3.300"; ...... private boolean isDvKitSupport() { boolean isSupport = true; try { //Obtain the running version of DV Kit. String version = DvKit.getVersion(); if (version.compareTo(CURRENT_KIT_VERSION) < 0) { //The current DV Kit version does not meet the app running requirements. isSupport = false; } } catch (NoClassDefFoundError e) { //The current running environment does not support the DV Kit. isSupport = false; Log.e(TAG, "DvKit not exist", e); } return isSupport; }

4. Apply for app permissions.

AndroidManifest.xml

<uses-permission android:name="android.permission.CAMERA" /> <uses-permission android:name="android.permission.RECORD_AUDIO" /> <uses-permission android:name="android.permission.VIBRATE" /> <uses-permission android:name="android.permission.BODY_SENSORS" /> <uses-permission android:name="com.huawei.permission.DISTRIBUTED_VIRTUALDEVICE" />

MainActivity.java

String[] permissions = new String[]{Manifest.permission.CAMERA, Manifest.permission.RECORD_AUDIO, Manifest.permission.BODY_SENSORS, " com.huawei.permission.DISTRIBUTED_VIRTUALDEVICE"}; ...... mPermissionList.clear(); for (int i = 0; i < permissions.length; i++) { if (ContextCompat.checkSelfPermission(MainActivity.this, permissions[i]) != PackageManager.PERMISSION_GRANTED) { mPermissionList.add(permissions[i]); } } if (mPermissionList.isEmpty()) { //The permission not granted is empty, that is, all permissions are granted. Intent intent = new Intent(MainActivity.this, DvKitDemoActivity.class); startActivity(intent); } else { //Permission request method. String[] permissions = mPermissionList.toArray(new String[mPermissionList.size()]);//Convert list to an array. requestPermissions(permissions, PERMISSIONS_REQUEST); } ...... //After obtaining the permission, open the DvKitDemo Activity. @Override public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) { if (requestCode == PERMISSIONS_REQUEST) { for (int i = 0; i < grantResults.length; i++) { if (grantResults[i] == PackageManager.PERMISSION_GRANTED) { mPermissionList.remove(permissions[i]); } } if (mPermissionList.isEmpty()) { Intent intent = new Intent(MainActivity.this, DvKitDemoActivity.class); startActivity(intent); } } super.onRequestPermissionsResult(requestCode, permissions, grantResults); }

5. Connect to the DV Kit service and subscribe to device capability status change events.

DvKitDemoActivity.java

//Set the discovery button. mStartDiscoveryButton.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { if (mVirtualDeviceManager == null) { addLog("WechatAdapter is null"); return; } //Invoke the discovery API. int ret = mVirtualDeviceManager.startDiscovery(discoveryCallback); addLog("start discovery result is " + ret); } }); ...... /** * Callback API for obtaining the discovered virtualized devices. */ private IDiscoveryCallback discoveryCallback = new IDiscoveryCallback() { @Override public void onFound(VirtualDevice device, int state) { if (device == null) { addLog("onDevice callback but device is null"); } else { //Save the discovered device to the container and display it on the GUI. if (!mVirtualDeviceMap.containsKey(device.getDeviceId())) { addLog("onDevice Found: " + device.getDeviceId() + " Name: " + device.getDeviceName() + " Type:" + device.getDeviceType()); mVirtualDeviceMap.put(device.getDeviceId(), device); handler.sendMessage(handler.obtainMessage(DEVICE_ADD, device)); } } } @Override public void onState(int state) { } };

6. Discover a device.

DvKitDemoActivity.java

//Set the discovery button. mStartDiscoveryButton.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { if (mVirtualDeviceManager == null) { addLog("WechatAdapter is null"); return; } //Invoke the discovery API. int ret = mVirtualDeviceManager.startDiscovery(discoveryCallback); addLog("start discovery result is " + ret); } }); ...... /** * Callback API for obtaining the discovered virtualized devices. */ private IDiscoveryCallback discoveryCallback = new IDiscoveryCallback() { @Override public void onFound(VirtualDevice device, int state) { if (device == null) { addLog("onDevice callback but device is null"); } else { //Save the discovered device to the container and display it on the GUI. if (!mVirtualDeviceMap.containsKey(device.getDeviceId())) { addLog("onDevice Found: " + device.getDeviceId() + " Name: " + device.getDeviceName() + " Type:" + device.getDeviceType()); mVirtualDeviceMap.put(device.getDeviceId(), device); handler.sendMessage(handler.obtainMessage(DEVICE_ADD, device)); } } } @Override public void onState(int state) { } };

7. Display device selection dialog box.

Any app that uses the HUAWEI DeviceVirtualization Kit must display the following dialog box for users to select capable devices to complete capability continuation. After devices are discovered, a device list should be displayed for the user to select, as shown in the following figure.

8. Enable the device capability.

DvKitDemoActivity.java

holder.camera_button.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { final String deviceId = (String) v.getTag(); VirtualDevice device = mVirtualDeviceMap.get(deviceId); if (device == null) { addLog("do not contains " + deviceId); return; } if (!cameraOpend.containsKey(deviceId) || !cameraOpend.get(deviceId)) { addLog("open camera " + device.getDeviceName()); //Enable the virtual camera. int ret = mVirtualDeviceManager.enableVirtualDevice(deviceId, EnumSet.of(CAMAERA), null); addLog("open camera result is " + ret); } else { ...... } } }); ...... /** * Callback API for observing changes in the device capability status (enabled or disabled). */ private IVirtualDeviceObserver observer = new IVirtualDeviceObserver() { //Callback when the device status changes. @Override public void onDeviceStateChange(VirtualDevice virtualDevice, int returncode) { } /** * Callback when the device capability status changes. */ @Override public void onDeviceCapabilityStateChange(VirtualDevice virtualDevice, Capability capability, int returncode) { if (returncode == EventType.EVENT_DEVICE_CAPABILITY_ENABLE) { //The app processing when the device capability is enabled successfully. onEnable(virtualDevice, capability); } else if (returncode == EventType.EVENT_DEVICE_CAPABILITY_DISABLE) { //The app processing logic when the device capability is disabled successfully. onDisable(virtualDevice, capability); } else { //The app processing logic when the device capability is abnormal. onError(virtualDevice, capability, returncode); } } ...... };

9. Use the virtual device capability through the Android API. The following are two examples.

DvKitDemoActivity.java

/** * The app processing when the device capability is enabled successfully. */ public void onEnable(VirtualDevice device, Capability capability) { switch (capability) { case CAMARACAMERA: //Camera is enabled. addLog("open camera success"); //Set the camera enabling status to true. cameraOpend.put(device.getDeviceId(), true); //Obtain the camera ID. String data = device.getData(Constants.ANDROID_CAMERAID_FRONT); addLog("open camera " + device.getDeviceName() + " cameraId " + data); //Open the virtual camera. Intent intent = new Intent(DvKitDemoActivity.this, RegitsterCameraAPI2.class); intent.putExtra("cameraId", data); Log.i(TAG, "cameraId is " + data); startActivity(intent); break; case DISPLAY: //The display capability is enabled successfully. Set the display enabling status to true. addLog("open display success"); displayOpend.put(device.getDeviceId(), true); break; case MIC: //The microphone capability is enabled successfully. Set the microphone enabling status to true. addLog("open mic success"); micOpend.put(device.getDeviceId(), true); break; case SPEAKER: //The speaker capability is enabled successfully. Set the speaker enabling status to true. addLog("open speaker success"); speakerOpend.put(device.getDeviceId(), true); break; case VIBRATE: //The vibration capability is enabled successfully. Set the vibration enabling status to true. addLog("open vibrate success"); speakerOpend.put(device.getDeviceId(), true); break; case SENSOR: //The sensor capability is enabled successfully. Set the sensor enabling status to true. addLog("open sensor success"); speakerOpend.put(device.getDeviceId(), true); break; case NOTIFICATION: //The notification capability is enabled successfully. Set the notification enabling status to true. addLog("open notification success"); speakerOpend.put(device.getDeviceId(), true); break; } }

a. This example shows how to obtain the camera preview streams of the virtual device by calling the Android Camera API2.
RegitsterCameraAPI2.java

private void openCamera(int width, int height) { ...... CameraManager manager = (CameraManager) getSystemService(Context.CAMERA_SERVICE); String cameraId; cameraId = chooseCameraId(); CameraCharacteristics characteristics = manager.getCameraCharacteristics(cameraId); fps = characteristics.get(CameraCharacteristics.CONTROL_AE_AVAILABLE_TARGET_FPS_RANGES); fpsList.clear(); for (int i = fps.length - 1; i >= 0; i--) { Log.i(TAG, "index: " + i + ", [" + fps[i].getLower() + ", " + fps[i].getUpper() + "]"); fpsList.add(fps[i]); } fpsAdapter.notifyDataSetChanged(); mPreviewSize = new Size(1920, 1080); Log.i(TAG, "openCamera, mPreviewSize width x mPreviewSize height = " + mPreviewSize.getWidth() + " x " + mPreviewSize.getHeight()); int orientation = getResources().getConfiguration().orientation; Log.i(TAG, "orientation is : " + orientation); if (orientation == Configuration.ORIENTATION_LANDSCAPE) { mTextureView.setAspectRatio(mPreviewSize.getWidth(), mPreviewSize.getHeight()); } else { mTextureView.setAspectRatio(mPreviewSize.getHeight(), mPreviewSize.getWidth()); } Log.i(TAG, "openCamera, mTextureView width x mTextureView height = " + mTextureView.getWidth() + " x " + mTextureView.getHeight()); Log.i(TAG, "openCamera, width x height = " + width + " x " + height); configureTransform(width, height); manager.openCamera(cameraId, mStateCallback, null); ...... } private String chooseCameraId() { return getIntent().getStringExtra("cameraId"); } ......

b. This example uses a message push API to send a message notification of the wearable device.
NotificationTest.java

DvNotificationService notificationService = (DvNotificationService) HiWearActivity.mDvKit.getKitService(VIRTUAL_NOTIFICATION_SERVICE); DvNotification notification = new DvNotification(); Map<String, Object> notificaitonProperty = new HashMap<>(); notificaitonProperty.put(DvNotification.KEY_PACKAGE_NAME, "packageName"); //Set the package name of the third-party app to distinguish the message source. notificaitonProperty.put(DvNotification.KEY_GUIDE_DISTANCE, 500); //Set the navigation distance. notificaitonProperty.put(DvNotification.KEY_DISTANCE_UNIT, "m"); //Set the navigation unit. notificaitonProperty.put(DvNotification.KEY_DIRECTION_INDEX, 1); //Set the index of the navigation icon. notificaitonProperty.put(DvNotification.KEY_GUIDE_TEXT, "turn left"); //Set the navigation message text. notificaitonProperty.put(DvNotification.KEY_VIBRATE, DvNotificationService.NORMAL_VIBRATION); //Set the vibration mode for the message. notification.setNotificationProperty(DvNotificationService.GUIDE_LAYOUT_TEMPLATE, notificaitonProperty); //Use this API to set the attributes of the navigation message. int res = notificationService.doNotification(deviceId, notificationId, notification, DvNotificationService.ADD_NOTIFY); //Send the notification to the device API.

10. Disable the virtual device capability. When an app does not need to use the virtual device capability, for example, when the app needs to switch back to the mobile phone capability, the app can disable the virtual device capability.

DvKitDemoActivity.java

holder.camera_button.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { final String deviceId = (String) v.getTag(); VirtualDevice device = mVirtualDeviceMap.get(deviceId); if (device == null) { addLog("do not contains " + deviceId); return; } if (!cameraOpend.containsKey(deviceId) || !cameraOpend.get(deviceId)) { ...... } else { ...... //Disable the virtual camera. int ret = mVirtualDeviceManager.disableVirtualDevice(deviceId, EnumSet.of(CAMAERA)); ...... } } }); ...... /** * Callback API for observing changes in the device capability status (enabled or disabled). */ private IVirtualDeviceObserver observer = new IVirtualDeviceObserver() { //Callback when the device status changes. @Override public void onDeviceStateChange(VirtualDevice virtualDevice, int returncode) { } /** * Callback when the device capability status changes. */ @Override public void onDeviceCapabilityStateChange(VirtualDevice virtualDevice, Capability capability, int returncode) { if (returncode == EventType.EVENT_DEVICE_CAPABILITY_ENABLE) { //The app processing when the device capability is enabled successfully. onEnable(virtualDevice, capability); } else if (returncode == EventType.EVENT_DEVICE_CAPABILITY_DISABLE) { //The app processing logic when the device capability is disabled successfully. onDisable(virtualDevice, capability); } else { //The app processing logic when the device capability is abnormal. onError(virtualDevice, capability, returncode); } } ...... };

11. Disconnect.

DvKitDemoActivity.java

public void onDestroy() { DvKit.getInstance().disConnect(); ...... }

You have successfully completed this Codelab and learned:

For more information, please click the following link:
Related documents

Download the source code for the demo that is used in this codelab

Download

Code copied