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.
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.
HUAWEI DeviceVirtualization Kit integration requires the following preparations:
For details, see DeviceVirtualization Kit Development Preparations.
Integrate DeviceVirtualization Kit by following the instructions provided in step 6 in DeviceVirtualization Kit Development Preparations.
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"/>
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;
}
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);
}
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) {
}
};
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) {
}
};
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.
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);
}
}
......
};
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.
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);
}
}
......
};
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