Merge "Camera: clarify depth camera requirement for OFFLINE_PROCESSING"
diff --git a/automotive/sv/1.0/Android.bp b/automotive/sv/1.0/Android.bp
new file mode 100644
index 0000000..769bdc6
--- /dev/null
+++ b/automotive/sv/1.0/Android.bp
@@ -0,0 +1,24 @@
+// This file is autogenerated by hidl-gen -Landroidbp.
+
+hidl_interface {
+ name: "android.hardware.automotive.sv@1.0",
+ root: "android.hardware",
+ vndk: {
+ enabled: true,
+ },
+ srcs: [
+ "types.hal",
+ "ISurroundViewStream.hal",
+ "ISurroundViewSession.hal",
+ "ISurroundView2dSession.hal",
+ "ISurroundView3dSession.hal",
+ "ISurroundViewService.hal",
+ ],
+ interfaces: [
+ "android.hidl.base@1.0",
+ "android.hardware.graphics.common@1.0",
+ "android.hardware.graphics.common@1.1",
+ "android.hardware.graphics.common@1.2",
+ ],
+ gen_java: true,
+}
diff --git a/automotive/sv/1.0/ISurroundView2dSession.hal b/automotive/sv/1.0/ISurroundView2dSession.hal
new file mode 100644
index 0000000..fa49674
--- /dev/null
+++ b/automotive/sv/1.0/ISurroundView2dSession.hal
@@ -0,0 +1,84 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.automotive.sv@1.0;
+
+import ISurroundViewSession;
+
+/**
+ * Interface representing a surround view 2d session.
+ *
+ * Surround view 2d provides a top/bird's eye view of the car and its surroundings.
+ */
+interface ISurroundView2dSession extends ISurroundViewSession {
+
+ /**
+ * Gets mapping information for 2d surround view.
+ *
+ * Mapping information maps the output frame of 2d surround view to actual dimensions
+ * covered on the ground. Mapping information is fixed for a car and is based upon its camera
+ * coverage. Mapping information can be used for doing overlays of objects in 3d space
+ * onto the surround view 2d output frame.
+ *
+ * @param sv2dConfig Configuration to set.
+ * @return sv2dMappingInfo mapping information of the 2d surround view.
+ */
+ get2dMappingInfo() generates (Sv2dMappingInfo sv2dMappingInfo);
+
+ /**
+ * Sets the configuration of 2d surround view.
+ *
+ * Configuration is used for supported different target use-cases of the surround view eg.
+ * fullscreen or preview. Default configuration is FULLSCREEN.
+ * A set config call can be performed at any time (before or after startStream) of the session.
+ * Once config change is complete, a CONFIG_CHANGED event is sent, after which
+ * all frames received will be of the updated config.
+ *
+ * @param sv2dConfig Configuration to set.
+ * @return svResult Returns OK if successful, appropriate error result otherwise.
+ */
+ set2dConfig(Sv2dConfig sv2dConfig) generates (SvResult svResult);
+
+ /**
+ * Gets the current configuration of the 2d surround view.
+ *
+ * Configuration is used for supported different target use-cases of the surround view eg.
+ * fullscreen view or preview. Use setConfig call to set a configuration.
+ *
+ * @return sv2dConfig the active current configuration of the 2d session.
+ */
+ get2dConfig() generates (Sv2dConfig sv2dConfig);
+
+ /**
+ * Projects points on camera image to surround view 2d image.
+ *
+ * Useful for mapping points detected on individual camera frames onto the surround view 2d
+ * output frame.
+ *
+ * @param cameraPoints List of camera pixel points to be projected in range including (0, 0)
+ * and (width - 1, height -1) of camera frame. If point is outside camera
+ frame INVALID_ARG error is returned.
+ * @param cameraId Id of the EvsCamera to use for projecting points. Id must be one of the
+ * cameras as returned by getCameraIds() else INVALID_ARG error is returned
+ * @return points2d Returns a list of 2d pixel points projecting into surround view 2d
+ * frame in the same order as cameraPoints. Point projected maybe outside
+ * surround view frame i.e. outside (0, 0) and
+ * (sv_width - 1, sv_height - 1). Points that do not project to ground
+ * plane are set with inValid true.
+ */
+ projectCameraPoints(vec<Point2dInt> cameraPoints, string cameraId) generates (
+ vec<Point2dFloat> points2d);
+};
diff --git a/automotive/sv/1.0/ISurroundView3dSession.hal b/automotive/sv/1.0/ISurroundView3dSession.hal
new file mode 100644
index 0000000..d2b0c53
--- /dev/null
+++ b/automotive/sv/1.0/ISurroundView3dSession.hal
@@ -0,0 +1,113 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.automotive.sv@1.0;
+
+import ISurroundViewSession;
+
+/**
+ * Interface representing a surround view 3d session.
+ *
+ * Surround view 3d provides a virtual view from any desired position in the 3d space around the
+ * car. Surround view 3d creates an approximate 3d surface around the car to match the surrounds
+ * and provides a virtual view as seen on this surface.
+ */
+interface ISurroundView3dSession extends ISurroundViewSession {
+
+ /**
+ * Sets the desired views of surround view 3d.
+ *
+ * Surround view 3d takes a list of desired virtual view points and provides an output frame
+ * for each view. Default view list is a single view from behind the car front facing in the
+ * front direction.
+ * A call to setViews() results in the views set by a previous call to be discarded.
+ * Each view set is identified by an Id which is returned with the corresponding output frame
+ * of that view.
+ * Clients can call setViews() at any stage of the session (before/after startStream). Client
+ * may continue to receive frames of previous views after setViews() call for a while and can
+ * identify updated set of views once effective using the view Id provided in the updated
+ * views frames.
+ *
+ * @param views List of desired views to generate output frames.
+ * @return svResult Returns OK if successful, appropriate error result otherwise.
+ */
+ setViews(vec<View3d> views) generates (SvResult svResult);
+
+ /**
+ * Sets the configuration of 3d surround view.
+ *
+ * Configuration is used for supported different target use-cases of the surround view eg.
+ * fullscreen view or preview. A set config call can be performed at anytime (before or after
+ * startStream) of the session.
+ * Once config change is complete, a CONFIG_CHANGED event is sent, after which
+ * all frames received will be of the updated config.
+ *
+ * @param sv3dConfig Configuration to set.
+ * @return svResult Returns OK if successful, appropriate error result otherwise.
+ */
+ set3dConfig(Sv3dConfig sv3dConfig) generates (SvResult svResult);
+
+ /**
+ * Gets the current configuration of the 3d surround view.
+ *
+ * Configuration is used for supported different target use-cases of the surround view eg.
+ * fullscreen view or preview. Use setConfig call to set a configuration.
+ *
+ * @return sv3dConfig The current active configuration of the 3d session.
+ */
+ get3dConfig() generates (Sv3dConfig sv3dConfig);
+
+ /**
+ * Updates 3d overlays in scene.
+ *
+ * updateOverlays() provides a way to set a 3d overlay object in the scene. An overlay is an
+ * 3d object in the scene which can be a visual indicator to provide additional information eg.
+ * parking sensor distance indicators or overlays for objects in scene.
+ *
+ * An overlay object is defined by a set of points (forming triangles) with some color and
+ * transparency values and each overlay is identified by an overlay Id.
+ * When an overlay with a new Id is passed, a new overlay is added to the scene.
+ * When an overlay with previous id is passed, its vertices/color are updated with passed data.
+ * If the overlay data is empty, the overlay is removed from the scene.
+ *
+ * @param overlaysData Object with shared memory containing overlays to add/update in the
+ * scene. Refer to OverlaysData structure for layout in shared memory.
+ * @return svResult Returns OK if successful, appropriate error result otherwise.
+ */
+ updateOverlays(OverlaysData overlaysData) generates (SvResult svResult);
+
+ /**
+ * Projects points on camera image to surround view 3D surface.
+ *
+ * Useful for mapping points detected on individual camera frames onto the surround view 3D
+ * surface, these 3d points can then be used to set overlays using the updateOverlays() for
+ * the detected objects in the scene.
+ * Note:
+ * 3d points returned are projected on an approximate 3d surface and do not provide the exact
+ * 3d location.
+ *
+ * @param cameraPoints List of camera pixel points to be projected in range including (0, 0)
+ * and (width - 1, height -1) of camera frame. If point is outside camera
+ frame INVALID_ARG error is returned.
+ * @param cameraId Id of the EvsCamera to use for projecting points. Id must be one of the
+ * cameras as returned by getCameraIds() else INVALID_ARG error is returned
+ * @return points3d Returns a list of 3d points on the approximate 3d surface in the
+ * automotive coordinate system in the same order as cameraPoints.
+ * Points that do not project to 3d surface are set with inValid true.
+ */
+ projectCameraPointsTo3dSurface(vec<Point2dInt> cameraPoints, string cameraId) generates (
+ vec<Point3dFloat> points3d);
+};
diff --git a/automotive/sv/1.0/ISurroundViewService.hal b/automotive/sv/1.0/ISurroundViewService.hal
new file mode 100644
index 0000000..7de0bd1
--- /dev/null
+++ b/automotive/sv/1.0/ISurroundViewService.hal
@@ -0,0 +1,71 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.automotive.sv@1.0;
+
+import ISurroundView2dSession;
+import ISurroundView3dSession;
+
+/**
+ * Interface representing entry point for surround view.
+ *
+ * Surround view service has two types of sessions 2d and 3d. Refer to their respective interface
+ * for more details.
+ */
+interface ISurroundViewService {
+
+ /**
+ * Gets a list of camera ids that are used for generating surround view.
+ * For 4 camera configuration, the cameras ids are ordered in clockwise direction
+ * when viewed from top of the car starting with the front camera. i.e. FRONT, RIGHT, REAR and
+ * LEFT. All other configurations must follow clockwise order.
+ *
+ * @result cameraIds List of camera ids that matching the Id of EVS Cameras used by service.
+ */
+ getCameraIds() generates (vec<string> cameraIds);
+
+ /**
+ * Starts a surround view 2d session.
+ *
+ * @result sv2dSession Returns a new 2d session that was created.
+ * result Returns OK if successful, appropriate error result otherwise.
+ */
+ start2dSession() generates (ISurroundView2dSession sv2dSession, SvResult result);
+
+ /**
+ * Stops a surround view 2d session.
+ *
+ * @param sv2dSession Valid 2d session to be stopped.
+ * @return svResult Returns OK if successful, appropriate error result otherwise.
+ */
+ stop2dSession(ISurroundView2dSession sv2dSession) generates (SvResult result);
+
+ /**
+ * Starts a surround view 3d session.
+ *
+ * @result sv3dSession Returns a new 3d session that was created.
+ * result Returns OK if successful, appropriate error result otherwise.
+ */
+ start3dSession() generates (ISurroundView3dSession sv3dSession, SvResult result);
+
+ /**
+ * Stops a surround view 2d session.
+ *
+ * @param sv2dSession Valid 2d session to be stopped.
+ * @return svResult Returns OK if successful, appropriate error result otherwise.
+ */
+ stop3dSession(ISurroundView3dSession sv3dSession) generates (SvResult result);
+};
diff --git a/automotive/sv/1.0/ISurroundViewSession.hal b/automotive/sv/1.0/ISurroundViewSession.hal
new file mode 100644
index 0000000..62cfac0
--- /dev/null
+++ b/automotive/sv/1.0/ISurroundViewSession.hal
@@ -0,0 +1,51 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.automotive.sv@1.0;
+
+import ISurroundViewStream;
+
+/**
+ * Common interface for surround view session extended by surround view 2d and 3d
+ * session.
+ */
+interface ISurroundViewSession {
+ /**
+ * Requests to start receiving surround view frames.
+ *
+ * For surround view 3d, setViews() must be set before calling startStream().
+ *
+ * @param stream Stream to receiving callbacks for the session.
+ * @return svResult Returns OK if successful, returns VIEW_NOT_SET if setViews() is not
+ * called for surround view 3d, appropriate error results otherwise.
+ */
+ startStream(ISurroundViewStream stream) generates (SvResult svResult);
+
+ /**
+ * Requests to stop stream.
+ *
+ * Frames may continue to arrive after call returns. Each must be returned until
+ * the closure of the stream is signaled by the ISurroundViewStream.
+ */
+ stopStream();
+
+ /**
+ * Signal from client that a frame, which was delivered by the stream, has been consumed.
+ *
+ * @param svFramesDesc Descriptor to signal done with frame.
+ */
+ oneway doneWithFrames(SvFramesDesc svFramesDesc);
+};
diff --git a/automotive/sv/1.0/ISurroundViewStream.hal b/automotive/sv/1.0/ISurroundViewStream.hal
new file mode 100644
index 0000000..22d610f
--- /dev/null
+++ b/automotive/sv/1.0/ISurroundViewStream.hal
@@ -0,0 +1,38 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.automotive.sv@1.0;
+
+/**
+ * Interface representing a surround view stream.
+ *
+ * This interface is to be implemented by client to receive callback for output frames and events.
+ */
+interface ISurroundViewStream {
+ /**
+ * Receives callback of surround view 2d/3d frames.
+ *
+ * @param svFramesDesc Frames descriptor containing the output frames.
+ */
+ oneway receiveFrames(SvFramesDesc svFramesDesc);
+
+ /**
+ * Receives callback for surround view events.
+ *
+ * @param svEvent Surround view event.
+ */
+ oneway notify(SvEvent svEvent);
+};
diff --git a/automotive/sv/1.0/default/Android.bp b/automotive/sv/1.0/default/Android.bp
new file mode 100644
index 0000000..8417949
--- /dev/null
+++ b/automotive/sv/1.0/default/Android.bp
@@ -0,0 +1,47 @@
+//
+// Copyright (C) 2020 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+cc_binary {
+ name: "android.hardware.automotive.sv@1.0-service",
+ vendor: true,
+ relative_install_path: "hw",
+ srcs: [
+ "service.cpp",
+ "SurroundViewService.cpp",
+ "SurroundView2dSession.cpp",
+ "SurroundView3dSession.cpp",
+ ],
+ init_rc: ["android.hardware.automotive.sv@1.0-service.rc"],
+ vintf_fragments: ["android.hardware.automotive.sv@1.0-service.xml"],
+ shared_libs: [
+ "android.hardware.automotive.sv@1.0",
+ "android.hidl.memory@1.0",
+ "libbase",
+ "libbinder",
+ "libcutils",
+ "libhardware",
+ "libhidlbase",
+ "liblog",
+ "libui",
+ "libutils",
+ "libhidlmemory",
+ ],
+
+ cflags: [
+ "-O0",
+ "-g",
+ ],
+}
diff --git a/automotive/sv/1.0/default/SurroundView2dSession.cpp b/automotive/sv/1.0/default/SurroundView2dSession.cpp
new file mode 100644
index 0000000..4f97598
--- /dev/null
+++ b/automotive/sv/1.0/default/SurroundView2dSession.cpp
@@ -0,0 +1,240 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "SurroundView2dSession.h"
+
+#include <utils/Log.h>
+#include <utils/SystemClock.h>
+
+namespace android {
+namespace hardware {
+namespace automotive {
+namespace sv {
+namespace V1_0 {
+namespace implementation {
+
+SurroundView2dSession::SurroundView2dSession() :
+ mStreamState(STOPPED) {
+ mEvsCameraIds = {"0" , "1", "2", "3"};
+
+ mConfig.width = 640;
+ mConfig.blending = SvQuality::HIGH;
+
+ framesRecord.frames.svBuffers.resize(1);
+ framesRecord.frames.svBuffers[0].viewId = 0;
+ framesRecord.frames.svBuffers[0].hardwareBuffer.nativeHandle =
+ new native_handle_t();
+ framesRecord.frames.svBuffers[0].hardwareBuffer.description[0] =
+ mConfig.width;
+ framesRecord.frames.svBuffers[0].hardwareBuffer.description[1] =
+ mConfig.width * 3 / 4;
+}
+
+// Methods from ::android::hardware::automotive::sv::V1_0::ISurroundViewSession
+Return<SvResult> SurroundView2dSession::startStream(
+ const sp<ISurroundViewStream>& stream) {
+ ALOGD("SurroundView2dSession::startStream");
+ std::lock_guard<std::mutex> lock(mAccessLock);
+
+ if (mStreamState != STOPPED) {
+ ALOGE("ignoring startVideoStream call"
+ "when a stream is already running.");
+ return SvResult::INTERNAL_ERROR;
+ }
+
+ mStream = stream;
+
+ ALOGD("Notify SvEvent::STREAM_STARTED");
+ mStream->notify(SvEvent::STREAM_STARTED);
+
+ // Start the frame generation thread
+ mStreamState = RUNNING;
+ mCaptureThread = std::thread([this](){ generateFrames(); });
+
+ return SvResult::OK;
+}
+
+Return<void> SurroundView2dSession::stopStream() {
+ ALOGD("SurroundView2dSession::stopStream");
+ std::unique_lock <std::mutex> lock(mAccessLock);
+
+ if (mStreamState == RUNNING) {
+ // Tell the GenerateFrames loop we want it to stop
+ mStreamState = STOPPING;
+
+ // Block outside the mutex until the "stop" flag has been acknowledged
+ // We won't send any more frames, but the client might still get some
+ // already in flight
+ ALOGD("Waiting for stream thread to end...");
+ lock.unlock();
+ mCaptureThread.join();
+ lock.lock();
+
+ mStreamState = STOPPED;
+ mStream = nullptr;
+ ALOGD("Stream marked STOPPED.");
+ }
+
+ return android::hardware::Void();
+}
+
+Return<void> SurroundView2dSession::doneWithFrames(
+ const SvFramesDesc& svFramesDesc){
+ ALOGD("SurroundView2dSession::doneWithFrames");
+ std::unique_lock <std::mutex> lock(mAccessLock);
+
+ framesRecord.inUse = false;
+
+ (void)svFramesDesc;
+ return android::hardware::Void();
+}
+
+// Methods from ISurroundView2dSession follow.
+Return<void> SurroundView2dSession::get2dMappingInfo(
+ get2dMappingInfo_cb _hidl_cb) {
+ ALOGD("SurroundView2dSession::get2dMappingInfo");
+ std::unique_lock <std::mutex> lock(mAccessLock);
+
+ Sv2dMappingInfo info;
+ info.width = 8; // keeps ratio to 4:3
+ info.height = 6;
+ info.center.isValid = true;
+ info.center.x = 0;
+ info.center.y = 0;
+ _hidl_cb(info);
+ return android::hardware::Void();
+}
+
+Return<SvResult> SurroundView2dSession::set2dConfig(
+ const Sv2dConfig& sv2dConfig) {
+ ALOGD("SurroundView2dSession::setConfig");
+ std::unique_lock <std::mutex> lock(mAccessLock);
+
+ mConfig.width = sv2dConfig.width;
+ mConfig.blending = sv2dConfig.blending;
+ ALOGD("Notify SvEvent::CONFIG_UPDATED");
+ mStream->notify(SvEvent::CONFIG_UPDATED);
+
+ return SvResult::OK;
+}
+
+Return<void> SurroundView2dSession::get2dConfig(get2dConfig_cb _hidl_cb) {
+ ALOGD("SurroundView2dSession::getConfig");
+ std::unique_lock <std::mutex> lock(mAccessLock);
+
+ _hidl_cb(mConfig);
+ return android::hardware::Void();
+}
+
+Return<void> SurroundView2dSession::projectCameraPoints(
+ const hidl_vec<Point2dInt>& points2dCamera,
+ const hidl_string& cameraId,
+ projectCameraPoints_cb _hidl_cb) {
+ ALOGD("SurroundView2dSession::projectCameraPoints");
+ std::unique_lock <std::mutex> lock(mAccessLock);
+
+ bool cameraIdFound = false;
+ for (auto evsCameraId : mEvsCameraIds) {
+ if (cameraId == evsCameraId) {
+ cameraIdFound = true;
+ ALOGI("Camera id found.");
+ break;
+ }
+ }
+
+ if (!cameraIdFound) {
+ ALOGE("Camera id not found.");
+ _hidl_cb(hidl_vec<Point2dFloat>());
+ return android::hardware::Void();
+ }
+
+ hidl_vec<Point2dFloat> outPoints;
+ outPoints.resize(points2dCamera.size());
+
+ int width = mConfig.width;
+ int height = mConfig.width * 3 / 4;
+ for (int i=0; i<points2dCamera.size(); i++) {
+ // Assuming all the points in the image frame can be projected into 2d
+ // Surround View space. Otherwise cannot.
+ if (points2dCamera[i].x < 0 || points2dCamera[i].y > width-1 ||
+ points2dCamera[i].x < 0 || points2dCamera[i].y > height-1) {
+ ALOGW("SurroundView2dSession::projectCameraPoints "
+ "gets invalid 2d camera points. Ignored");
+ outPoints[i].isValid = false;
+ outPoints[i].x = 10000;
+ outPoints[i].y = 10000;
+ } else {
+ outPoints[i].isValid = true;
+ outPoints[i].x = 0;
+ outPoints[i].y = 0;
+ }
+ }
+
+ _hidl_cb(outPoints);
+ return android::hardware::Void();
+}
+
+void SurroundView2dSession::generateFrames() {
+ ALOGD("SurroundView2dSession::generateFrames");
+
+ int sequenceId = 0;
+
+ while(true) {
+ {
+ std::lock_guard<std::mutex> lock(mAccessLock);
+
+ if (mStreamState != RUNNING) {
+ // Break out of our main thread loop
+ break;
+ }
+
+ framesRecord.frames.svBuffers[0].hardwareBuffer.description[0] =
+ mConfig.width;
+ framesRecord.frames.svBuffers[0].hardwareBuffer.description[1] =
+ mConfig.width * 3 / 4;
+ }
+
+ usleep(100 * 1000);
+
+ framesRecord.frames.timestampNs = elapsedRealtimeNano();
+ framesRecord.frames.sequenceId = sequenceId++;
+
+ {
+ std::lock_guard<std::mutex> lock(mAccessLock);
+
+ if (framesRecord.inUse) {
+ ALOGD("Notify SvEvent::FRAME_DROPPED");
+ mStream->notify(SvEvent::FRAME_DROPPED);
+ } else {
+ framesRecord.inUse = true;
+ mStream->receiveFrames(framesRecord.frames);
+ }
+ }
+ }
+
+ // If we've been asked to stop, send an event to signal the actual
+ // end of stream
+ ALOGD("Notify SvEvent::STREAM_STOPPED");
+ mStream->notify(SvEvent::STREAM_STOPPED);
+}
+
+} // namespace implementation
+} // namespace V1_0
+} // namespace sv
+} // namespace automotive
+} // namespace hardware
+} // namespace android
+
diff --git a/automotive/sv/1.0/default/SurroundView2dSession.h b/automotive/sv/1.0/default/SurroundView2dSession.h
new file mode 100644
index 0000000..ee751e7
--- /dev/null
+++ b/automotive/sv/1.0/default/SurroundView2dSession.h
@@ -0,0 +1,98 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <android/hardware/automotive/sv/1.0/types.h>
+#include <android/hardware/automotive/sv/1.0/ISurroundViewStream.h>
+#include <android/hardware/automotive/sv/1.0/ISurroundView2dSession.h>
+#include <hidl/MQDescriptor.h>
+#include <hidl/Status.h>
+
+#include <thread>
+
+using namespace ::android::hardware::automotive::sv::V1_0;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+using ::android::hardware::hidl_vec;
+using ::android::sp;
+using ::std::mutex;
+
+namespace android {
+namespace hardware {
+namespace automotive {
+namespace sv {
+namespace V1_0 {
+namespace implementation {
+
+class SurroundView2dSession : public ISurroundView2dSession {
+public:
+ SurroundView2dSession();
+
+ // Methods from ::android::hardware::automotive::sv::V1_0::ISurroundViewSession.
+ Return<SvResult> startStream(
+ const sp<ISurroundViewStream>& stream) override;
+ Return<void> stopStream() override;
+ Return<void> doneWithFrames(const SvFramesDesc& svFramesDesc) override;
+
+ // Methods from ISurroundView2dSession follow.
+ Return<void> get2dMappingInfo(get2dMappingInfo_cb _hidl_cb) override;
+ Return<SvResult> set2dConfig(const Sv2dConfig& sv2dConfig) override;
+ Return<void> get2dConfig(get2dConfig_cb _hidl_cb) override;
+ Return<void> projectCameraPoints(
+ const hidl_vec<Point2dInt>& points2dCamera,
+ const hidl_string& cameraId,
+ projectCameraPoints_cb _hidl_cb) override;
+
+ // TODO(tanmayp): Make private and add set/get method.
+ // Stream subscribed for the session.
+ sp<ISurroundViewStream> mStream;
+
+private:
+ void generateFrames();
+
+ enum StreamStateValues {
+ STOPPED,
+ RUNNING,
+ STOPPING,
+ DEAD,
+ };
+ StreamStateValues mStreamState;
+
+ Sv2dConfig mConfig;
+
+ std::thread mCaptureThread; // The thread we'll use to synthesize frames
+
+ struct FramesRecord {
+ SvFramesDesc frames;
+ bool inUse = false;
+ };
+
+ FramesRecord framesRecord;
+
+ // Synchronization necessary to deconflict mCaptureThread from the main service thread
+ std::mutex mAccessLock;
+
+ std::vector<std::string> mEvsCameraIds;
+};
+
+} // namespace implementation
+} // namespace V1_0
+} // namespace sv
+} // namespace automotive
+} // namespace hardware
+} // namespace android
+
diff --git a/automotive/sv/1.0/default/SurroundView3dSession.cpp b/automotive/sv/1.0/default/SurroundView3dSession.cpp
new file mode 100644
index 0000000..da36f32
--- /dev/null
+++ b/automotive/sv/1.0/default/SurroundView3dSession.cpp
@@ -0,0 +1,310 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "SurroundView3dSession.h"
+
+#include <set>
+
+#include <utils/Log.h>
+#include <utils/SystemClock.h>
+
+#include <android/hidl/memory/1.0/IMemory.h>
+#include <hidlmemory/mapping.h>
+
+using ::android::hidl::memory::V1_0::IMemory;
+using ::android::hardware::hidl_memory;
+
+namespace android {
+namespace hardware {
+namespace automotive {
+namespace sv {
+namespace V1_0 {
+namespace implementation {
+
+SurroundView3dSession::SurroundView3dSession() :
+ mStreamState(STOPPED){
+
+ mEvsCameraIds = {"0" , "1", "2", "3"};
+
+ mConfig.width = 640;
+ mConfig.height = 480;
+ mConfig.carDetails = SvQuality::HIGH;
+
+ framesRecord.frames.svBuffers.resize(1);
+ framesRecord.frames.svBuffers[0].viewId = 0;
+ framesRecord.frames.svBuffers[0].hardwareBuffer.nativeHandle = new native_handle_t();
+ framesRecord.frames.svBuffers[0].hardwareBuffer.description[0] = mConfig.width;
+ framesRecord.frames.svBuffers[0].hardwareBuffer.description[1] = mConfig.height;
+}
+
+// Methods from ::android::hardware::automotive::sv::V1_0::ISurroundViewSession.
+Return<SvResult> SurroundView3dSession::startStream(
+ const sp<ISurroundViewStream>& stream) {
+ ALOGD("SurroundView3dSession::startStream");
+ std::lock_guard<std::mutex> lock(mAccessLock);
+
+ if (mStreamState != STOPPED) {
+ ALOGE("ignoring startVideoStream call when a stream is already running.");
+ return SvResult::INTERNAL_ERROR;
+ }
+
+ if (mViews.empty()) {
+ ALOGE("No views have been set for current Surround View 3d Session. "
+ "Please call setViews before starting the stream.");
+ return SvResult::VIEW_NOT_SET;
+ }
+
+ mStream = stream;
+
+ ALOGD("Notify SvEvent::STREAM_STARTED");
+ mStream->notify(SvEvent::STREAM_STARTED);
+
+ // Start the frame generation thread
+ mStreamState = RUNNING;
+ mCaptureThread = std::thread([this](){ generateFrames(); });
+
+ return SvResult::OK;
+}
+
+Return<void> SurroundView3dSession::stopStream() {
+ ALOGD("SurroundView3dSession::stopStream");
+ std::unique_lock <std::mutex> lock(mAccessLock);
+
+ if (mStreamState == RUNNING) {
+ // Tell the GenerateFrames loop we want it to stop
+ mStreamState = STOPPING;
+
+ // Block outside the mutex until the "stop" flag has been acknowledged
+ // We won't send any more frames, but the client might still get some already in flight
+ ALOGD("Waiting for stream thread to end...");
+ lock.unlock();
+ mCaptureThread.join();
+ lock.lock();
+
+ mStreamState = STOPPED;
+ mStream = nullptr;
+ ALOGD("Stream marked STOPPED.");
+ }
+
+ return android::hardware::Void();
+}
+
+Return<void> SurroundView3dSession::doneWithFrames(
+ const SvFramesDesc& svFramesDesc){
+ ALOGD("SurroundView3dSession::doneWithFrames");
+ std::unique_lock <std::mutex> lock(mAccessLock);
+
+ framesRecord.inUse = false;
+
+ (void)svFramesDesc;
+ return android::hardware::Void();
+}
+
+// Methods from ISurroundView3dSession follow.
+Return<SvResult> SurroundView3dSession::setViews(const hidl_vec<View3d>& views) {
+ ALOGD("SurroundView3dSession::stopStream");
+ std::unique_lock <std::mutex> lock(mAccessLock);
+
+ mViews.resize(views.size());
+ for (int i=0; i<views.size(); i++) {
+ mViews[i] = views[i];
+ }
+
+ return SvResult::OK;
+}
+
+Return<SvResult> SurroundView3dSession::set3dConfig(const Sv3dConfig& sv3dConfig) {
+ ALOGD("SurroundView3dSession::set3dConfig");
+ std::unique_lock <std::mutex> lock(mAccessLock);
+
+ mConfig.width = sv3dConfig.width;
+ mConfig.height = sv3dConfig.height;
+ mConfig.carDetails = sv3dConfig.carDetails;
+ ALOGD("Notify SvEvent::CONFIG_UPDATED");
+ mStream->notify(SvEvent::CONFIG_UPDATED);
+
+ return SvResult::OK;
+}
+
+Return<void> SurroundView3dSession::get3dConfig(get3dConfig_cb _hidl_cb) {
+ ALOGD("SurroundView3dSession::get3dConfig");
+ std::unique_lock <std::mutex> lock(mAccessLock);
+
+ _hidl_cb(mConfig);
+ return android::hardware::Void();
+}
+
+bool VerifyOverlayData(const OverlaysData& overlaysData) {
+ // Check size of shared memory matches overlaysMemoryDesc.
+ const int kVertexSize = 16;
+ const int kIdSize = 2;
+ int memDescSize = 0;
+ for (auto overlayMemDesc : overlaysData.overlaysMemoryDesc) {
+ memDescSize += kIdSize + kVertexSize * overlayMemDesc.verticesCount;
+ }
+ if (memDescSize != overlaysData.overlaysMemory.size()) {
+ ALOGE("shared memory and overlaysMemoryDesc size mismatch.");
+ return false;
+ }
+
+ // Map memory.
+ sp<IMemory> pSharedMemory = mapMemory(overlaysData.overlaysMemory);
+ if(pSharedMemory.get() == nullptr) {
+ ALOGE("mapMemory failed.");
+ return false;
+ }
+
+ // Get Data pointer.
+ uint8_t* pData = (uint8_t*)((void*)pSharedMemory->getPointer());
+ if (pData == nullptr) {
+ ALOGE("Shared memory getPointer() failed.");
+ return false;
+ }
+
+ int idOffset = 0;
+ std::set<uint16_t> overlayIdSet;
+ for (auto overlayMemDesc : overlaysData.overlaysMemoryDesc) {
+
+ if (overlayIdSet.find(overlayMemDesc.id) != overlayIdSet.end()) {
+ ALOGE("Duplicate id within memory descriptor.");
+ return false;
+ }
+ overlayIdSet.insert(overlayMemDesc.id);
+
+ if(overlayMemDesc.verticesCount < 3) {
+ ALOGE("Less than 3 vertices.");
+ return false;
+ }
+
+ if (overlayMemDesc.overlayPrimitive == OverlayPrimitive::TRIANGLES &&
+ overlayMemDesc.verticesCount % 3 != 0) {
+ ALOGE("Triangles primitive does not have vertices multiple of 3.");
+ return false;
+ }
+
+ uint16_t overlayId = *((uint16_t*)(pData + idOffset));
+
+ if (overlayId != overlayMemDesc.id) {
+ ALOGE("Overlay id mismatch %d , %d", overlayId, overlayMemDesc.id);
+ return false;
+ }
+
+ idOffset += kIdSize + (kVertexSize * overlayMemDesc.verticesCount);
+ }
+
+ return true;
+}
+
+Return<SvResult> SurroundView3dSession::updateOverlays(
+ const OverlaysData& overlaysData) {
+
+ if(!VerifyOverlayData(overlaysData)) {
+ ALOGE("VerifyOverlayData failed.");
+ return SvResult::INVALID_ARG;
+ }
+
+ return SvResult::OK;
+}
+
+Return<void> SurroundView3dSession::projectCameraPointsTo3dSurface(
+ const hidl_vec<Point2dInt>& cameraPoints,
+ const hidl_string& cameraId,
+ projectCameraPointsTo3dSurface_cb _hidl_cb) {
+
+ std::vector<Point3dFloat> points3d;
+ bool cameraIdFound = false;
+ for (auto evsCameraId : mEvsCameraIds) {
+ if (cameraId == evsCameraId) {
+ cameraIdFound = true;
+ ALOGI("Camera id found.");
+ break;
+ }
+ }
+
+ if (!cameraIdFound) {
+ ALOGE("Camera id not found.");
+ _hidl_cb(points3d);
+ return android::hardware::Void();
+ }
+
+ for (const auto cameraPoint : cameraPoints) {
+ Point3dFloat point3d;
+ point3d.isValid = true;
+
+ if (cameraPoint.x < 0 || cameraPoint.x >= mConfig.width-1 ||
+ cameraPoint.y < 0 || cameraPoint.y >= mConfig.height-1) {
+ ALOGE("Camera point out of bounds.");
+ point3d.isValid = false;
+ }
+ points3d.push_back(point3d);
+ }
+ _hidl_cb(points3d);
+ return android::hardware::Void();
+}
+
+void SurroundView3dSession::generateFrames() {
+ ALOGD("SurroundView3dSession::generateFrames");
+
+ int sequenceId = 0;
+
+ while(true) {
+ {
+ std::lock_guard<std::mutex> lock(mAccessLock);
+
+ if (mStreamState != RUNNING) {
+ // Break out of our main thread loop
+ break;
+ }
+ }
+
+ usleep(100 * 1000);
+
+ framesRecord.frames.timestampNs = elapsedRealtimeNano();
+ framesRecord.frames.sequenceId = sequenceId++;
+
+ framesRecord.frames.svBuffers.resize(mViews.size());
+ for (int i=0; i<mViews.size(); i++) {
+ framesRecord.frames.svBuffers[i].viewId = mViews[i].viewId;
+ framesRecord.frames.svBuffers[i].hardwareBuffer.nativeHandle = new native_handle_t();
+ framesRecord.frames.svBuffers[i].hardwareBuffer.description[0] = mConfig.width; // width
+ framesRecord.frames.svBuffers[i].hardwareBuffer.description[1] = mConfig.height; // height
+ }
+
+ {
+ std::lock_guard<std::mutex> lock(mAccessLock);
+
+ if (framesRecord.inUse) {
+ ALOGD("Notify SvEvent::FRAME_DROPPED");
+ mStream->notify(SvEvent::FRAME_DROPPED);
+ } else {
+ framesRecord.inUse = true;
+ mStream->receiveFrames(framesRecord.frames);
+ }
+ }
+ }
+
+ // If we've been asked to stop, send an event to signal the actual end of stream
+ ALOGD("Notify SvEvent::STREAM_STOPPED");
+ mStream->notify(SvEvent::STREAM_STOPPED);
+}
+
+} // namespace implementation
+} // namespace V1_0
+} // namespace sv
+} // namespace automotive
+} // namespace hardware
+} // namespace android
+
diff --git a/automotive/sv/1.0/default/SurroundView3dSession.h b/automotive/sv/1.0/default/SurroundView3dSession.h
new file mode 100644
index 0000000..5c638db
--- /dev/null
+++ b/automotive/sv/1.0/default/SurroundView3dSession.h
@@ -0,0 +1,100 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <android/hardware/automotive/sv/1.0/types.h>
+#include <android/hardware/automotive/sv/1.0/ISurroundViewStream.h>
+#include <android/hardware/automotive/sv/1.0/ISurroundView3dSession.h>
+#include <hidl/MQDescriptor.h>
+#include <hidl/Status.h>
+
+#include <thread>
+
+using namespace ::android::hardware::automotive::sv::V1_0;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+using ::android::hardware::hidl_vec;
+using ::android::sp;
+using ::std::mutex;
+
+namespace android {
+namespace hardware {
+namespace automotive {
+namespace sv {
+namespace V1_0 {
+namespace implementation {
+
+class SurroundView3dSession : public ISurroundView3dSession {
+public:
+ SurroundView3dSession();
+
+ // Methods from ::android::hardware::automotive::sv::V1_0::ISurroundViewSession.
+ Return<SvResult> startStream(
+ const sp<ISurroundViewStream>& stream) override;
+ Return<void> stopStream() override;
+ Return<void> doneWithFrames(const SvFramesDesc& svFramesDesc) override;
+
+ // Methods from ISurroundView3dSession follow.
+ Return<SvResult> setViews(const hidl_vec<View3d>& views) override;
+ Return<SvResult> set3dConfig(const Sv3dConfig& sv3dConfig) override;
+ Return<void> get3dConfig(get3dConfig_cb _hidl_cb) override;
+ Return<SvResult> updateOverlays(const OverlaysData& overlaysData);
+ Return<void> projectCameraPointsTo3dSurface(
+ const hidl_vec<Point2dInt>& cameraPoints,
+ const hidl_string& cameraId,
+ projectCameraPointsTo3dSurface_cb _hidl_cb);
+
+ // Stream subscribed for the session.
+ // TODO(tanmayp): Make private and add set/get method.
+ sp<ISurroundViewStream> mStream;
+
+private:
+ void generateFrames();
+
+ enum StreamStateValues {
+ STOPPED,
+ RUNNING,
+ STOPPING,
+ DEAD,
+ };
+ StreamStateValues mStreamState;
+
+ std::thread mCaptureThread; // The thread we'll use to synthesize frames
+
+ struct FramesRecord {
+ SvFramesDesc frames;
+ bool inUse = false;
+ };
+
+ FramesRecord framesRecord;
+
+ // Synchronization necessary to deconflict mCaptureThread from the main service thread
+ std::mutex mAccessLock;
+
+ std::vector<View3d> mViews;
+
+ Sv3dConfig mConfig;
+
+ std::vector<std::string> mEvsCameraIds;
+};
+
+} // namespace implementation
+} // namespace V1_0
+} // namespace sv
+} // namespace automotive
+} // namespace hardware
+} // namespace android
diff --git a/automotive/sv/1.0/default/SurroundViewService.cpp b/automotive/sv/1.0/default/SurroundViewService.cpp
new file mode 100644
index 0000000..fe89dd5
--- /dev/null
+++ b/automotive/sv/1.0/default/SurroundViewService.cpp
@@ -0,0 +1,91 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "SurroundViewService.h"
+
+#include <utils/Log.h>
+
+namespace android {
+namespace hardware {
+namespace automotive {
+namespace sv {
+namespace V1_0 {
+namespace implementation {
+
+const std::string kCameraIds[] = {"0", "1", "2", "3"};
+
+Return<void> SurroundViewService::getCameraIds(getCameraIds_cb _hidl_cb) {
+ std::vector<hidl_string> cameraIds = {kCameraIds[0], kCameraIds[1],
+ kCameraIds[2], kCameraIds[3]};
+ _hidl_cb(cameraIds);
+ return android::hardware::Void();
+}
+
+Return<void> SurroundViewService::start2dSession(start2dSession_cb _hidl_cb) {
+ ALOGD("SurroundViewService::start2dSession");
+ if (mSurroundView2dSession != nullptr) {
+ ALOGW("Only one 2d session is supported at the same time");
+ _hidl_cb(nullptr, SvResult::INTERNAL_ERROR);
+ } else {
+ mSurroundView2dSession = new SurroundView2dSession();
+ _hidl_cb(mSurroundView2dSession, SvResult::OK);
+ }
+ return android::hardware::Void();
+}
+
+Return<SvResult> SurroundViewService::stop2dSession(
+ const sp<ISurroundView2dSession>& sv2dSession) {
+ ALOGD("SurroundViewService::stop2dSession");
+ if (sv2dSession != nullptr && sv2dSession == mSurroundView2dSession) {
+ mSurroundView2dSession = nullptr;
+ return SvResult::OK;
+ } else {
+ ALOGE("Invalid arg for stop2dSession");
+ return SvResult::INVALID_ARG;
+ }
+}
+
+Return<void> SurroundViewService::start3dSession(start3dSession_cb _hidl_cb) {
+ ALOGD("SurroundViewService::start3dSession");
+ if (mSurroundView3dSession != nullptr) {
+ ALOGW("Only one 3d session is supported at the same time");
+ _hidl_cb(nullptr, SvResult::INTERNAL_ERROR);
+ } else {
+ mSurroundView3dSession = new SurroundView3dSession();
+ _hidl_cb(mSurroundView3dSession, SvResult::OK);
+ }
+ return android::hardware::Void();
+}
+
+Return<SvResult> SurroundViewService::stop3dSession(
+ const sp<ISurroundView3dSession>& sv3dSession) {
+ ALOGD("SurroundViewService::stop3dSession");
+ if (sv3dSession != nullptr && sv3dSession == mSurroundView3dSession) {
+ mSurroundView3dSession = nullptr;
+ return SvResult::OK;
+ } else {
+ ALOGE("Invalid arg for stop3dSession");
+ return SvResult::INVALID_ARG;
+ }
+}
+
+} // namespace implementation
+} // namespace V1_0
+} // namespace sv
+} // namespace automotive
+} // namespace hardware
+} // namespace android
+
diff --git a/automotive/sv/1.0/default/SurroundViewService.h b/automotive/sv/1.0/default/SurroundViewService.h
new file mode 100644
index 0000000..9e0e151
--- /dev/null
+++ b/automotive/sv/1.0/default/SurroundViewService.h
@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include "SurroundView2dSession.h"
+#include "SurroundView3dSession.h"
+
+#include <android/hardware/automotive/sv/1.0/types.h>
+#include <android/hardware/automotive/sv/1.0/ISurroundViewService.h>
+#include <android/hardware/automotive/sv/1.0/ISurroundViewStream.h>
+#include <android/hardware/automotive/sv/1.0/ISurroundView2dSession.h>
+#include <android/hardware/automotive/sv/1.0/ISurroundView3dSession.h>
+#include <hidl/MQDescriptor.h>
+#include <hidl/Status.h>
+
+using namespace ::android::hardware::automotive::sv::V1_0;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+using ::android::sp;
+
+namespace android {
+namespace hardware {
+namespace automotive {
+namespace sv {
+namespace V1_0 {
+namespace implementation {
+
+class SurroundViewService : public ISurroundViewService {
+public:
+ // Methods from ::android::hardware::automotive::sv::V1_0::ISurroundViewService follow.
+ Return<void> getCameraIds(getCameraIds_cb _hidl_cb) override;
+ Return<void> start2dSession(start2dSession_cb _hidl_cb) override;
+ Return<SvResult> stop2dSession(
+ const sp<ISurroundView2dSession>& sv2dSession) override;
+
+ Return<void> start3dSession(start3dSession_cb _hidl_cb) override;
+ Return<SvResult> stop3dSession(
+ const sp<ISurroundView3dSession>& sv3dSession) override;
+
+private:
+ sp<SurroundView2dSession> mSurroundView2dSession;
+ sp<SurroundView3dSession> mSurroundView3dSession;
+};
+
+} // namespace implementation
+} // namespace V1_0
+} // namespace sv
+} // namespace automotive
+} // namespace hardware
+} // namespace android
diff --git a/automotive/sv/1.0/default/android.hardware.automotive.sv@1.0-service.rc b/automotive/sv/1.0/default/android.hardware.automotive.sv@1.0-service.rc
new file mode 100644
index 0000000..e822017
--- /dev/null
+++ b/automotive/sv/1.0/default/android.hardware.automotive.sv@1.0-service.rc
@@ -0,0 +1,5 @@
+service sv_service /vendor/bin/hw/android.hardware.automotive.sv@1.0-service
+ class hal
+ user automotive_evs
+ group automotive_evs
+ disabled
diff --git a/automotive/sv/1.0/default/android.hardware.automotive.sv@1.0-service.xml b/automotive/sv/1.0/default/android.hardware.automotive.sv@1.0-service.xml
new file mode 100644
index 0000000..ba8e5ac
--- /dev/null
+++ b/automotive/sv/1.0/default/android.hardware.automotive.sv@1.0-service.xml
@@ -0,0 +1,11 @@
+<manifest version="1.0" type="device">
+ <hal format="hidl">
+ <name>android.hardware.automotive.sv</name>
+ <transport>hwbinder</transport>
+ <version>1.0</version>
+ <interface>
+ <name>ISurroundViewService</name>
+ <instance>default</instance>
+ </interface>
+ </hal>
+</manifest>
diff --git a/automotive/sv/1.0/default/service.cpp b/automotive/sv/1.0/default/service.cpp
new file mode 100644
index 0000000..fae7425
--- /dev/null
+++ b/automotive/sv/1.0/default/service.cpp
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "android.hardware.automotive.sv@1.0-service"
+
+#include <android/hardware/automotive/sv/1.0/ISurroundViewStream.h>
+#include <android/hardware_buffer.h>
+#include <hidl/HidlTransportSupport.h>
+#include <log/log.h>
+#include <thread>
+#include <ui/GraphicBuffer.h>
+#include <utils/Errors.h>
+#include <utils/StrongPointer.h>
+#include <utils/SystemClock.h>
+
+#include "SurroundViewService.h"
+
+// libhidl:
+using android::hardware::configureRpcThreadpool;
+using android::hardware::joinRpcThreadpool;
+
+// implementation:
+using android::hardware::automotive::sv::V1_0::implementation::SurroundViewService;
+
+int main() {
+ ALOGI("ISurroundViewService default implementation is starting");
+ android::sp<ISurroundViewService> service = new SurroundViewService();
+
+ configureRpcThreadpool(1, true /* callerWillJoin */);
+
+ // Register our service -- if somebody is already registered by our name,
+ // they will be killed (their thread pool will throw an exception).
+ android::status_t status = service->registerAsService();
+
+ LOG_ALWAYS_FATAL_IF(status != android::OK,
+ "Could not register default Surround View Service (%d)",
+ status);
+
+ joinRpcThreadpool();
+
+ // In normal operation, we don't expect the thread pool to exit
+ ALOGE("Surround View Service is shutting down");
+ return 1;
+}
diff --git a/automotive/sv/1.0/types.hal b/automotive/sv/1.0/types.hal
new file mode 100644
index 0000000..573bf11
--- /dev/null
+++ b/automotive/sv/1.0/types.hal
@@ -0,0 +1,351 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.automotive.sv@1.0;
+
+import android.hardware.graphics.common@1.2::HardwareBuffer;
+
+/** Structure for translation with x, y and z units. */
+struct Translation {
+ float x;
+ float y;
+ float z;
+};
+
+/**
+ * Structure for rotation expressed as quaternions.
+ * Convention used: Unit quaternion with hamilton convention.
+ */
+struct RotationQuat {
+ float x;
+ float y;
+ float z;
+ float w;
+};
+
+/** Structure representing a 2D point with integers. Units are pixels. */
+struct Point2dInt {
+ uint32_t x;
+ uint32_t y;
+};
+
+/** Structure representing a 2D point with floats. */
+struct Point2dFloat {
+ /** Boolean flag to indicate the (x, y) data is valid. */
+ bool isValid;
+
+ /** (x, y) data is only valid if isValid is true. Units are pixels or milli-meters. */
+ float x;
+ float y;
+};
+
+/** Structure representing a 3D point with floats. */
+struct Point3dFloat {
+ /** Boolean flag to indicate the (x, y, z) data is valid. */
+ bool isValid;
+
+ /**
+ * (x, y, z) data is only valid if isValid is true. Units are milli-meters.
+ */
+ float x;
+ float y;
+ float z;
+};
+
+/**
+ * Structure defining the pose in 3D space.
+ */
+struct Pose {
+ /**
+ * Rotation part of the pose, expressed as a unit quaternion.
+ */
+ RotationQuat rotation;
+
+ /**
+ * Translation part of the pose, in (x, y, z) format with milli-meter units.
+ */
+ Translation translation;
+};
+
+/**
+ * Struct defining a virtual view in the 3d space around the car.
+ */
+struct View3d {
+ /**
+ * Id to identify each custom view, this is passed along in each result SvBuffer.
+ * Recommend client to have a unique id for each different view.
+ */
+ uint32_t viewId;
+
+ /**
+ * Pose of the view. Describes the orientation and location of a virtual view relative to the
+ * android automotive coordinate system:
+ * https://source.android.com/devices/sensors/sensor-types#auto_axes
+ * The virtual view axes are defined as +Y as look-at direction, +X as right direction and
+ * +Z as up direction.
+ * The rotation and translation of the virtual view axes w.r.t the android automotive axes is
+ * specified by the rotation and tranlation component of the pose respectively.
+ * Example: A virtual view points to the right face of the car, located on right side of
+ * the car at (4, 2, 0) and is upright w.r.t the ground :
+ * ______
+ * front | |
+ * | car | ↑X
+ * | ↑Y | Y←∘ view
+ * rear | ∘→X | (4,2)
+ * |(0,0) |
+ * |______|
+ *
+ * Here the view axes are rotated by 90 counter-clockwise w.r.t android automotive axes.
+ * For this example the rotation and translation will be:
+ * Rotation = + 90 degrees around Z axis = (0.7071, 0, 0, 0.7071) as a unit quaternion.
+ * Translation = (4, 2, 0) in meters = (2000, 4000, 0) in milli-meters.
+ */
+ Pose pose;
+
+ /**
+ * Horizontal field of view of the virtual view in degrees. Vertical fov is scaled accordingly
+ * to maintain the aspect ratio of the output frame. Must be in range (20,
+ */
+ float horizontalFov;
+};
+
+/**
+ * Memory Buffer that stores the output of a single view from 2d/3d surround view.
+ */
+struct SvBuffer {
+ /**
+ * viewId identifying the view as passed by the client in setViews() call for
+ * surround view 3d. Id value is 0 for 2d surround view frame.
+ */
+ uint32_t viewId;
+
+ /** Hardware buffer containing the surround view 2d/3d result. */
+ HardwareBuffer hardwareBuffer;
+};
+
+/**
+ * Structure describing a set of frames to be returned as output from 2d/3d surround view.
+ */
+struct SvFramesDesc {
+ /**
+ * Elapsed real-time nanoseconds of earliest camera frame from the set of camera
+ * frames used to generate the view.
+ */
+ uint64_t timestampNs;
+
+ /**
+ * Incremental counter for client to keep track of frames.
+ */
+ uint32_t sequenceId;
+
+ /**
+ * Frames generated with different views.
+ * 2d surround view has only a single svBuffer with Id 0.
+ */
+ vec<SvBuffer> svBuffers;
+};
+
+/**
+ * Enumerator for list of result returns by surround view .
+ */
+enum SvResult : uint32_t {
+ /** Operation was successful. */
+ OK = 0,
+
+ /** Invalid argument to function was provided. */
+ INVALID_ARG,
+
+ /** Error indicating the particular operation is not supported. */
+ NOT_SUPPORTED,
+
+ /** Error indicating view not set before starting stream. */
+ VIEW_NOT_SET,
+
+ /**
+ * Error indicating system does not currently have enough resources to
+ * allocate for a new requested session.
+ * Clients may retry request for session if resources become available.
+ */
+ NO_RESOURCE,
+
+ /** Internal error in surround view service. */
+ INTERNAL_ERROR,
+};
+
+/**
+ * Enumerator listing events for surround view.
+ */
+enum SvEvent : uint32_t {
+ STREAM_STARTED = 1,
+
+ STREAM_STOPPED,
+
+ /**
+ * Event sent after service switches to an updated config, all frames
+ * streamed after this event are of the updated config.
+ */
+ CONFIG_UPDATED,
+
+ /** Each frame dropped will be notified with this event. */
+ FRAME_DROPPED,
+
+ /**
+ * Timeout event occurs if any individual camera stream has a timeout.
+ * Frames will not be delivered and clients must stop the stream.
+ */
+ TIMEOUT,
+};
+
+/**
+ * Structure defining the mapping information for 2d surround view.
+ *
+ * Mapping information provides the area on ground (width and height) and
+ * position w.r.t the car that the surround view 2d covers. This can be used for
+ * mapping (linear transformation) with other sensors whose data is available in
+ * the car coordinate system (eg. Ultrasonics).
+ * Axes and origin are as per the android automotive axes:
+ * https://source.android.com/devices/sensors/sensor-types#auto_axes
+ */
+struct Sv2dMappingInfo {
+ /** Width in milli-meters of the 2d surround view along the ground plane. */
+ float width;
+
+ /** Height in milli-meters of the 2d surround view along the ground plane. */
+ float height;
+
+ /**
+ * Coordinates (x, y) of the center of the view in android automotive coordinate system on the
+ * ground plane. Units are milli-meters.
+ */
+ Point2dFloat center;
+};
+
+/**
+ * Enumerator for quality presets for 2d/3d surround view.
+ * Details of each preset are specified in the respective 2d/3d config structures.
+ */
+enum SvQuality : uint32_t {
+ HIGH = 0,
+ LOW,
+};
+
+/** Structure for surround view 2d configuration. */
+struct Sv2dConfig {
+ /**
+ * Desired output width in pixels. Must be in range (0, 4096].
+ * Height is computed keeping the aspect ratio of the mapping info,
+ * Example: If width = 1080 px and mapping_width = 5000 mm, mapping_height = 10000 mm.
+ * then, height = width * (mapping_height / mapping_width) = 2160 px.
+ * Height is set to the floor value in case of (mapping_height / mapping_width) is not integer.
+ * Mapping width, height is fixed for a car and is based on camera parameters and their ground
+ * coverage.
+ */
+ uint32_t width;
+
+ /**
+ * Blending quality preset to use.
+ * HIGH: High quality blending (eg. multiband blending) that consumes more resources.
+ * LOW: Low quality blending (eg. alpha blending) that consumes less resources.
+ */
+ SvQuality blending;
+};
+
+/** Structure for surround view 3d configuration. */
+struct Sv3dConfig {
+ /** Desired output width in pixels. Must be in range (0, 4096]. */
+ uint32_t width;
+
+ /** Desired output height in pixels. Must be in range (0, 4096]. */
+ uint32_t height;
+
+ /**
+ * Car model rendering details level.
+ * HIGH: Rendering includes shadows and reflections. Default option.
+ * LOW: Rendering with no shadows and reflections.
+ */
+ SvQuality carDetails;
+};
+
+/**
+ * Enumerator for a list of overlay primitives.
+ *
+ * Given a list of vertices for an overlay, a primitive type defines which vertices are used to form
+ * the surfaces of the overlay object.
+ */
+enum OverlayPrimitive : uint32_t {
+ /**
+ * Consecutive vertices picked in order 3 at a time form a triangle.
+ * Eg: In a list of vertices (V1, V2, V3, V4, V5, V6)
+ * (V1, V2, V3) form a triangle and (V4, V5, V6) form a triangle.
+ */
+ TRIANGLES = 0,
+
+ /**
+ * Every 3 consecutive vertices form a triangle.
+ * Example in a list of vertices V1, V2, V3, V4, V5, V6
+ * (V1, V2, V3), (V2, V3, V4), (V3, V4, V5) and (V4, V5, V6) form triangles.
+ */
+ TRIANGLES_STRIP,
+};
+
+/**
+ * Structure identifying an overlay and describing the size and arrangement of its data in
+ * shared memory.
+ */
+struct OverlayMemoryDesc {
+ /** Identifier of the overlay. */
+ uint16_t id;
+
+ /** Number of vertices in the overlay. */
+ uint32_t verticesCount;
+
+ /** Primitive for the overlay. */
+ OverlayPrimitive overlayPrimitive;
+};
+
+/**
+ * Structure containing the overlays data in shared memory.
+ */
+struct OverlaysData {
+ /** List of overlay memory descriptors, describing the data in the shared memory */
+ vec<OverlayMemoryDesc> overlaysMemoryDesc;
+
+ /**
+ * Shared memory object containing a list of vertices for each overlay as described by
+ * overlaysMemoryDesc.
+ *
+ * Each vertex comprises of:
+ * | PositionX | PositionY | PositionZ | RGBA |
+ * | float | float | float | 4 * uint8_t |
+ *
+ * Each vertex is of 3 floats and 4 bytes = 16 bytes.
+ *
+ * Layout of vertices in shared memory is in order:
+ *
+ * Bytes: | 0-1 | 2-18 | 19-34 | 35-50 | 51-66 | 67-68 | 69-84 | 85-100 | 101-116 |...
+ * Data: | id1 | V1 | V2 | V3 | V4 | id2 | V1 | V2 | V3 |...
+ * | overlay1 | overlay 2 |
+ *
+ * The order of overlays must match the order as specified in the overlaysMemoryDesc.
+ * The number of vertices each overlay has must match the verticesCount in overlaysMemoryDesc.
+ * The id must match the id specificed in the OverlayMemoryDesc. This is used for verification.
+ * For each overlay the number of vertices must be 3 or greater.
+ * For TRIANGLES primitive the number of vertices must be a multiple of 3.
+ * The overlay vertices are grouped as per the overlayPrimitive specified in overlaysMemoryDesc,
+ * eg: If primitive is TRIANGLES, (V1, V2, V3) and (V4, V5, V6) form a triangle.
+ */
+ memory overlaysMemory;
+};
diff --git a/automotive/sv/1.0/vts/functional/Android.bp b/automotive/sv/1.0/vts/functional/Android.bp
new file mode 100644
index 0000000..0e5d3df
--- /dev/null
+++ b/automotive/sv/1.0/vts/functional/Android.bp
@@ -0,0 +1,41 @@
+//
+// Copyright (C) 2020 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+cc_test {
+ name: "VtsHalSurroundViewV1_0TargetTest",
+ srcs: [
+ "VtsHalSurroundViewV1_0TargetTest.cpp",
+ "SurroundViewStreamHandler.cpp",
+ ],
+ defaults: ["VtsHalTargetTestDefaults"],
+ static_libs: [
+ "libnativewindow",
+ "android.hardware.automotive.sv@1.0",
+ "android.hardware.graphics.common@1.0",
+ "android.hardware.graphics.common@1.1",
+ "android.hardware.graphics.common@1.2",
+ ],
+ shared_libs: [
+ "android.hidl.allocator@1.0",
+ "android.hidl.memory@1.0",
+ "libhidlmemory",
+ ],
+ test_suites: ["general-tests", "vts-core"],
+ cflags: [
+ "-O0",
+ "-g",
+ ],
+}
diff --git a/automotive/sv/1.0/vts/functional/SurroundViewStreamHandler.cpp b/automotive/sv/1.0/vts/functional/SurroundViewStreamHandler.cpp
new file mode 100644
index 0000000..cb45caa
--- /dev/null
+++ b/automotive/sv/1.0/vts/functional/SurroundViewStreamHandler.cpp
@@ -0,0 +1,113 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "SurroundViewStreamHandler.h"
+
+#include <utils/Log.h>
+
+using std::lock_guard;
+
+SurroundViewServiceHandler::SurroundViewServiceHandler(sp<ISurroundViewSession> pSession) :
+ mSession(pSession),
+ mReceiveFramesCount(0),
+ mDoNotReturnFrames(false) {
+ // Nothing but member initialization
+}
+
+Return<void> SurroundViewServiceHandler::notify(SvEvent svEvent) {
+ ALOGD("SurroundViewServiceHandler::notify %d", svEvent);
+
+ lock_guard<mutex> lock(mLock);
+ switch (svEvent) {
+ case SvEvent::STREAM_STARTED:
+ case SvEvent::CONFIG_UPDATED:
+ case SvEvent::STREAM_STOPPED:
+ case SvEvent::FRAME_DROPPED:
+ case SvEvent::TIMEOUT:
+ mReceivedEvents.emplace_back(svEvent);
+ break;
+ default:
+ ALOGI("[SurroundViewLog] Received other event");
+ }
+
+ return android::hardware::Void();
+}
+
+Return<void> SurroundViewServiceHandler::receiveFrames(const SvFramesDesc& svFramesDesc) {
+ ALOGD("SurroundViewServiceHandler::receiveFrames");
+
+ lock_guard<mutex> lock(mLock);
+ unsigned long timestampNs = svFramesDesc.timestampNs;
+ unsigned sequenceId = svFramesDesc.sequenceId;
+ ALOGD("receiveFrames count: %d", mReceiveFramesCount);
+ ALOGD("timestampNs: %lu, sequenceId: %u", timestampNs, sequenceId);
+ if (mReceiveFramesCount != 0
+ && (mLastReceivedFrames.timestampNs >= svFramesDesc.timestampNs
+ || mLastReceivedFrames.sequenceId >= svFramesDesc.sequenceId)) {
+ mAllFramesValid = false;
+ ALOGD("The incoming frames are with invalid timestamp or sequenceId!");
+ }
+
+ for (int i=0; i<svFramesDesc.svBuffers.size(); i++) {
+ if (svFramesDesc.svBuffers[i].hardwareBuffer.nativeHandle == nullptr) {
+ mAllFramesValid = false;
+ ALOGD("The incoming frames are with invalid nativeHandle!");
+ break;
+ }
+ }
+
+ mReceiveFramesCount++;
+
+ // Store all the information except for the handle
+ mLastReceivedFrames.timestampNs = svFramesDesc.timestampNs;
+ mLastReceivedFrames.sequenceId = svFramesDesc.sequenceId;
+ mLastReceivedFrames.svBuffers.resize(svFramesDesc.svBuffers.size());
+ for (int i=0; i<svFramesDesc.svBuffers.size(); i++) {
+ mLastReceivedFrames.svBuffers[i].viewId = svFramesDesc.svBuffers[i].viewId;
+ mLastReceivedFrames.svBuffers[i].hardwareBuffer.description =
+ svFramesDesc.svBuffers[i].hardwareBuffer.description;
+ }
+
+ if (!mDoNotReturnFrames) {
+ mSession->doneWithFrames(svFramesDesc);
+ }
+
+ return android::hardware::Void();
+}
+
+bool SurroundViewServiceHandler::checkEventReceived(SvEvent svEvent) {
+ ALOGD("SurroundViewServiceHandler::checkEventReceived");
+ int size = mReceivedEvents.size(); // work around
+ ALOGD("Received event number: %d", size);
+ auto iter = find(mReceivedEvents.begin(), mReceivedEvents.end(), svEvent);
+ return iter != mReceivedEvents.end();
+}
+
+SvFramesDesc SurroundViewServiceHandler::getLastReceivedFrames() {
+ return mLastReceivedFrames;
+}
+
+int SurroundViewServiceHandler::getReceiveFramesCount() {
+ return mReceiveFramesCount;
+}
+
+bool SurroundViewServiceHandler::areAllFramesValid() {
+ return mAllFramesValid;
+}
+
+void SurroundViewServiceHandler::setDoNotReturnFrames(bool flag) {
+ mDoNotReturnFrames = flag;
+}
diff --git a/automotive/sv/1.0/vts/functional/SurroundViewStreamHandler.h b/automotive/sv/1.0/vts/functional/SurroundViewStreamHandler.h
new file mode 100644
index 0000000..7d3f61d
--- /dev/null
+++ b/automotive/sv/1.0/vts/functional/SurroundViewStreamHandler.h
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef SURROUND_VIEW_STREAM_HANDLER_H
+#define SURROUND_VIEW_STREAM_HANDLER_H
+
+#include <android/hardware/automotive/sv/1.0/types.h>
+#include <android/hardware/automotive/sv/1.0/ISurroundViewStream.h>
+#include <android/hardware/automotive/sv/1.0/ISurroundViewSession.h>
+
+#include <thread>
+#include <vector>
+
+using std::vector;
+using std::mutex;
+using android::hardware::Return;
+using android::sp;
+using namespace ::android::hardware::automotive::sv::V1_0;
+
+class SurroundViewServiceHandler : public ISurroundViewStream {
+public:
+ SurroundViewServiceHandler(sp<ISurroundViewSession> session);
+
+ Return<void> notify(SvEvent svEvent) override;
+ Return<void> receiveFrames(const SvFramesDesc& svFramesDesc) override;
+
+ bool checkEventReceived(SvEvent svEvent);
+ SvFramesDesc getLastReceivedFrames();
+ int getReceiveFramesCount();
+ bool areAllFramesValid();
+ void setDoNotReturnFrames(bool flag);
+
+private:
+ mutex mLock;
+
+ vector<SvEvent> mReceivedEvents;
+ sp<ISurroundViewSession> mSession;
+ SvFramesDesc mLastReceivedFrames; // only use timestampNs and sequenceId
+ int mReceiveFramesCount; // TODO(haoxiangl): figure out a better name
+ bool mAllFramesValid = true;
+ bool mDoNotReturnFrames;
+};
+
+#endif //SURROUND_VIEW_STREAM_HANDLER_H
diff --git a/automotive/sv/1.0/vts/functional/VtsHalSurroundViewV1_0TargetTest.cpp b/automotive/sv/1.0/vts/functional/VtsHalSurroundViewV1_0TargetTest.cpp
new file mode 100644
index 0000000..b1b9d16
--- /dev/null
+++ b/automotive/sv/1.0/vts/functional/VtsHalSurroundViewV1_0TargetTest.cpp
@@ -0,0 +1,1137 @@
+//
+// Copyright (C) 2020 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+#define LOG_TAG "VtsHalSurroundViewTest"
+
+#include <android/hardware/automotive/sv/1.0/types.h>
+#include <android/hardware/automotive/sv/1.0/ISurroundViewService.h>
+#include <android/hardware/automotive/sv/1.0/ISurroundViewStream.h>
+#include <android/hardware/automotive/sv/1.0/ISurroundView2dSession.h>
+#include <android/hardware/automotive/sv/1.0/ISurroundView3dSession.h>
+#include <android/hardware_buffer.h>
+#include <android/hidl/allocator/1.0/IAllocator.h>
+#include <android/hidl/memory/1.0/IMemory.h>
+#include <hidlmemory/mapping.h>
+#include <math.h>
+#include <utils/Log.h>
+
+#include <gtest/gtest.h>
+#include <hidl/GtestPrinter.h>
+#include <hidl/ServiceManagement.h>
+
+#include "SurroundViewStreamHandler.h"
+
+using namespace ::android::hardware::automotive::sv::V1_0;
+using ::android::sp;
+using ::android::hardware::hidl_vec;
+using ::android::hardware::hidl_string;
+using ::android::hidl::allocator::V1_0::IAllocator;
+using ::android::hidl::memory::V1_0::IMemory;
+using ::android::hardware::hidl_memory;
+
+const int kVertexByteSize = (3 * sizeof(float)) + 4;
+const int kIdByteSize = 2;
+
+// The main test class for Surround View Service
+class SurroundViewHidlTest : public ::testing::TestWithParam<std::string> {
+public:
+ virtual void SetUp() override {
+ mSurroundViewService = ISurroundViewService::getService(GetParam());
+ ASSERT_NE(mSurroundViewService.get(), nullptr);
+ }
+
+ virtual void TearDown() override {}
+
+ sp<ISurroundViewService> mSurroundViewService; // Every test needs access to the service
+};
+
+TEST_P(SurroundViewHidlTest, startAndStop2dSession) {
+ ALOGD("SurroundViewHidlTest::startAndStop2dSession");
+ sp<ISurroundView2dSession> surroundView2dSession;
+ mSurroundViewService->start2dSession(
+ [&surroundView2dSession](
+ const sp<ISurroundView2dSession>& session, SvResult result) {
+ ASSERT_EQ(result, SvResult::OK);
+ surroundView2dSession = session;
+ });
+
+ SvResult result = mSurroundViewService->stop2dSession(surroundView2dSession);
+ ASSERT_EQ(result, SvResult::OK);
+}
+
+TEST_P(SurroundViewHidlTest, stopInvalid2dSession) {
+ ALOGD("SurroundViewHidlTest::stopInvalid2dSession");
+ sp<ISurroundView2dSession> surroundView2dSession;
+ SvResult result = mSurroundViewService->stop2dSession(surroundView2dSession);
+ ASSERT_NE(result, SvResult::OK);
+}
+
+TEST_P(SurroundViewHidlTest, startAndStop2dStream) {
+ ALOGD("SurroundViewHidlTest::startAndStop2dStream");
+ sp<ISurroundView2dSession> surroundView2dSession;
+ mSurroundViewService->start2dSession(
+ [&surroundView2dSession](
+ const sp<ISurroundView2dSession>& session, SvResult result) {
+ ASSERT_EQ(result, SvResult::OK);
+ surroundView2dSession = session;
+ });
+
+ sp<SurroundViewServiceHandler> handler =
+ new SurroundViewServiceHandler(surroundView2dSession);
+
+ SvResult result = surroundView2dSession->startStream(handler);
+ EXPECT_EQ(result, SvResult::OK);
+
+ sleep(5);
+
+ EXPECT_TRUE(handler->checkEventReceived(SvEvent::STREAM_STARTED));
+ EXPECT_GT(handler->getReceiveFramesCount(), 0);
+
+ surroundView2dSession->stopStream();
+
+ sleep(1);
+ EXPECT_TRUE(handler->checkEventReceived(SvEvent::STREAM_STOPPED));
+
+ result = mSurroundViewService->stop2dSession(surroundView2dSession);
+ EXPECT_EQ(result, SvResult::OK);
+}
+
+TEST_P(SurroundViewHidlTest, start2dStreamWithoutReturningFrames) {
+ ALOGD("SurroundViewHidlTest::start2dStreamWithoutReturningFrames");
+ sp<ISurroundView2dSession> surroundView2dSession;
+ mSurroundViewService->start2dSession(
+ [&surroundView2dSession](
+ const sp<ISurroundView2dSession>& session, SvResult result) {
+ ASSERT_EQ(result, SvResult::OK);
+ surroundView2dSession = session;
+ });
+
+ sp<SurroundViewServiceHandler> handler =
+ new SurroundViewServiceHandler(surroundView2dSession);
+ handler->setDoNotReturnFrames(true);
+
+ SvResult result = surroundView2dSession->startStream(handler);
+ EXPECT_EQ(result, SvResult::OK);
+
+ sleep(5);
+
+ EXPECT_TRUE(handler->checkEventReceived(SvEvent::STREAM_STARTED));
+ EXPECT_TRUE(handler->checkEventReceived(SvEvent::FRAME_DROPPED));
+ EXPECT_GT(handler->getReceiveFramesCount(), 0);
+
+ surroundView2dSession->stopStream();
+
+ sleep(1);
+ EXPECT_TRUE(handler->checkEventReceived(SvEvent::STREAM_STOPPED));
+
+ result = mSurroundViewService->stop2dSession(surroundView2dSession);
+ EXPECT_EQ(result, SvResult::OK);
+}
+
+TEST_P(SurroundViewHidlTest, duplicateStart2dStream) {
+ ALOGD("SurroundViewHidlTest, duplicateStart2dStream");
+ sp<ISurroundView2dSession> surroundView2dSession;
+ mSurroundViewService->start2dSession(
+ [&surroundView2dSession](
+ const sp<ISurroundView2dSession>& session, SvResult result) {
+ ASSERT_EQ(result, SvResult::OK);
+ surroundView2dSession = session;
+ });
+
+ sp<SurroundViewServiceHandler> handler =
+ new SurroundViewServiceHandler(surroundView2dSession);
+
+ SvResult result = surroundView2dSession->startStream(handler);
+ EXPECT_EQ(result, SvResult::OK);
+
+ result = surroundView2dSession->startStream(handler);
+ EXPECT_NE(result, SvResult::OK);
+
+ surroundView2dSession->stopStream();
+ mSurroundViewService->stop2dSession(surroundView2dSession);
+}
+
+TEST_P(SurroundViewHidlTest, stopInvalid2dStream) {
+ ALOGD("SurroundViewHidlTest, stopInvalid2dStream");
+ sp<ISurroundView2dSession> surroundView2dSession;
+ mSurroundViewService->start2dSession(
+ [&surroundView2dSession](
+ const sp<ISurroundView2dSession>& session, SvResult result) {
+ ASSERT_EQ(result, SvResult::OK);
+ surroundView2dSession = session;
+ });
+
+ sp<SurroundViewServiceHandler> handler =
+ new SurroundViewServiceHandler(surroundView2dSession);
+
+ surroundView2dSession->stopStream();
+ mSurroundViewService->stop2dSession(surroundView2dSession);
+}
+
+TEST_P(SurroundViewHidlTest, validate2dSvFramesDesc) {
+ ALOGD("SurroundViewHidlTest, validate2dSvFramesDesc");
+ sp<ISurroundView2dSession> surroundView2dSession;
+ mSurroundViewService->start2dSession(
+ [&surroundView2dSession](
+ const sp<ISurroundView2dSession>& session, SvResult result) {
+ ASSERT_EQ(result, SvResult::OK);
+ surroundView2dSession = session;
+ });
+
+ sp<SurroundViewServiceHandler> handler =
+ new SurroundViewServiceHandler(surroundView2dSession);
+
+ SvResult result = surroundView2dSession->startStream(handler);
+ EXPECT_EQ(result, SvResult::OK);
+
+ sleep(5);
+
+ // Validate timestampNs and sequenceId
+ EXPECT_GT(handler->getReceiveFramesCount(), 0);
+ EXPECT_TRUE(handler->areAllFramesValid());
+
+ // Validate 2d SvFramesDesc. Do not compare nativeHandle since it is not
+ // stored and already verified on the fly.
+ SvFramesDesc frames = handler->getLastReceivedFrames();
+ EXPECT_EQ(frames.svBuffers.size(), 1);
+
+ SvBuffer svBuffer2d = frames.svBuffers[0];
+ EXPECT_EQ(svBuffer2d.viewId, 0);
+
+ const AHardwareBuffer_Desc* pDesc =
+ reinterpret_cast<const AHardwareBuffer_Desc *>(&svBuffer2d.hardwareBuffer.description);
+ float mapWidth, mapHeight;
+ surroundView2dSession->get2dMappingInfo([&mapWidth, &mapHeight] (Sv2dMappingInfo info) {
+ mapWidth = info.width;
+ mapHeight = info.height;
+ });
+ EXPECT_EQ(pDesc->height, floor(pDesc->width * (mapHeight / mapWidth)));
+
+ // Clean up
+ surroundView2dSession->stopStream();
+ result = mSurroundViewService->stop2dSession(surroundView2dSession);
+}
+
+TEST_P(SurroundViewHidlTest, get2dMappingInfo) {
+ ALOGD("SurroundViewHidlTest, get2dMappingInfo");
+ sp<ISurroundView2dSession> surroundView2dSession;
+ mSurroundViewService->start2dSession(
+ [&surroundView2dSession](
+ const sp<ISurroundView2dSession>& session, SvResult result) {
+ ASSERT_EQ(result, SvResult::OK);
+ surroundView2dSession = session;
+ });
+
+ surroundView2dSession->get2dMappingInfo([] (Sv2dMappingInfo info) {
+ EXPECT_GT(info.width, 0);
+ EXPECT_GT(info.height, 0);
+ });
+
+ mSurroundViewService->stop2dSession(surroundView2dSession);
+}
+
+TEST_P(SurroundViewHidlTest, set2dConfigResolution) {
+ ALOGD("SurroundViewHidlTest, set2dConfigResolution");
+ sp<ISurroundView2dSession> surroundView2dSession;
+ mSurroundViewService->start2dSession(
+ [&surroundView2dSession](
+ const sp<ISurroundView2dSession>& session, SvResult result) {
+ ASSERT_EQ(result, SvResult::OK);
+ surroundView2dSession = session;
+ });
+
+ sp<SurroundViewServiceHandler> handler =
+ new SurroundViewServiceHandler(surroundView2dSession);
+
+ SvResult result = surroundView2dSession->startStream(handler);
+ EXPECT_EQ(result, SvResult::OK);
+
+ sleep(1);
+
+ // Change config
+ Sv2dConfig config;
+ config.width = 1920;
+ config.blending = SvQuality::HIGH;
+ surroundView2dSession->set2dConfig(config);
+
+ sleep(1);
+
+ EXPECT_TRUE(handler->checkEventReceived(SvEvent::CONFIG_UPDATED));
+
+ // Check width has been changed but not the ratio
+ SvFramesDesc frames = handler->getLastReceivedFrames();
+ EXPECT_EQ(frames.svBuffers.size(), 1);
+ SvBuffer svBuffer2d = frames.svBuffers[0];
+ EXPECT_EQ(svBuffer2d.viewId, 0);
+ const AHardwareBuffer_Desc* pDesc =
+ reinterpret_cast<const AHardwareBuffer_Desc *>(&svBuffer2d.hardwareBuffer.description);
+ EXPECT_EQ(pDesc->width, config.width);
+
+ float mapWidth, mapHeight;
+ surroundView2dSession->get2dMappingInfo([&mapWidth, &mapHeight] (Sv2dMappingInfo info) {
+ mapWidth = info.width;
+ mapHeight = info.height;
+ });
+ EXPECT_EQ(pDesc->height, floor (pDesc->width * (mapHeight / mapWidth)));
+
+ // Clean up
+ surroundView2dSession->stopStream();
+ mSurroundViewService->stop2dSession(surroundView2dSession);
+}
+
+TEST_P(SurroundViewHidlTest, set2dConfigBlending) {
+ ALOGD("SurroundViewHidlTest, set2dConfigBlending");
+ sp<ISurroundView2dSession> surroundView2dSession;
+ mSurroundViewService->start2dSession(
+ [&surroundView2dSession](
+ const sp<ISurroundView2dSession>& session, SvResult result) {
+ ASSERT_EQ(result, SvResult::OK);
+ surroundView2dSession = session;
+ });
+
+ sp<SurroundViewServiceHandler> handler =
+ new SurroundViewServiceHandler(surroundView2dSession);
+
+ SvResult result = surroundView2dSession->startStream(handler);
+ EXPECT_EQ(result, SvResult::OK);
+
+ sleep(1);
+
+ // Get the width before config changed
+ int oldWidth;
+ SvFramesDesc frames = handler->getLastReceivedFrames();
+ EXPECT_EQ(frames.svBuffers.size(), 1);
+ SvBuffer svBuffer2d = frames.svBuffers[0];
+ const AHardwareBuffer_Desc* pDesc =
+ reinterpret_cast<const AHardwareBuffer_Desc *>(&svBuffer2d.hardwareBuffer.description);
+ oldWidth = pDesc->width;
+
+ // Change config
+ Sv2dConfig config;
+ config.width = oldWidth;
+ config.blending = SvQuality::LOW;
+ surroundView2dSession->set2dConfig(config);
+
+ sleep(1);
+
+ EXPECT_TRUE(handler->checkEventReceived(SvEvent::CONFIG_UPDATED));
+
+ Sv2dConfig retConfig;
+ surroundView2dSession->get2dConfig([&retConfig] (Sv2dConfig config) {
+ retConfig.width = config.width;
+ retConfig.blending = config.blending;
+ });
+
+ // Check config blending has been changed but not the width
+ EXPECT_EQ(retConfig.blending, config.blending);
+ EXPECT_EQ(retConfig.width, oldWidth);
+
+ // Clean up
+ surroundView2dSession->stopStream();
+ mSurroundViewService->stop2dSession(surroundView2dSession);
+}
+
+TEST_P(SurroundViewHidlTest, projectCameraPointsWithValidCameraId) {
+ ALOGD("SurroundViewHidlTest, projectCameraPointsWithValidCameraId");
+ sp<ISurroundView2dSession> surroundView2dSession;
+ mSurroundViewService->start2dSession(
+ [&surroundView2dSession](
+ const sp<ISurroundView2dSession>& session, SvResult result) {
+ ASSERT_EQ(result, SvResult::OK);
+ surroundView2dSession = session;
+ });
+
+ hidl_vec<hidl_string> cameraIds;
+ mSurroundViewService->getCameraIds([&cameraIds](
+ const hidl_vec<hidl_string>& camIds) {
+ cameraIds = camIds;
+ });
+
+ sp<SurroundViewServiceHandler> handler =
+ new SurroundViewServiceHandler(surroundView2dSession);
+
+ SvResult result = surroundView2dSession->startStream(handler);
+ EXPECT_EQ(result, SvResult::OK);
+
+ sleep(1);
+
+ // Get the width and height of the frame
+ int width, height;
+ SvFramesDesc frames = handler->getLastReceivedFrames();
+ EXPECT_EQ(frames.svBuffers.size(), 1);
+ SvBuffer svBuffer2d = frames.svBuffers[0];
+ const AHardwareBuffer_Desc* pDesc =
+ reinterpret_cast<const AHardwareBuffer_Desc *>(&svBuffer2d.hardwareBuffer.description);
+ width = pDesc->width;
+ height = pDesc->height;
+
+ float mapWidth, mapHeight, mapCenter[2];
+ surroundView2dSession->get2dMappingInfo(
+ [&mapWidth, &mapHeight, &mapCenter] (Sv2dMappingInfo info) {
+ mapWidth = info.width;
+ mapHeight = info.height;
+ mapCenter[0] = info.center.x;
+ mapCenter[1] = info.center.y;
+ });
+
+ // Set one valid point and one invalid point
+ hidl_vec<Point2dInt> points2dCamera;
+ points2dCamera.resize(2);
+ points2dCamera[0].x = 0;
+ points2dCamera[0].y = 0;
+ points2dCamera[1].x = width * 2;
+ points2dCamera[1].y = height * 2;
+
+ surroundView2dSession->projectCameraPoints(
+ points2dCamera,
+ cameraIds[0],
+ [&mapWidth, &mapHeight, &mapCenter] (
+ const hidl_vec<Point2dFloat>& outPoints) {
+ // Make sure point[0] is valid.
+ EXPECT_TRUE(outPoints[0].isValid);
+ EXPECT_GE(outPoints[0].x, mapCenter[0] - mapWidth);
+ EXPECT_LE(outPoints[0].x, mapCenter[0] + mapWidth);
+ EXPECT_GE(outPoints[0].y, mapCenter[1] - mapHeight);
+ EXPECT_LE(outPoints[0].y, mapCenter[1] + mapHeight);
+
+ // Make sure point[1] is invalid.
+ EXPECT_FALSE(outPoints[1].isValid);
+ });
+
+ // Clean up
+ surroundView2dSession->stopStream();
+ mSurroundViewService->stop2dSession(surroundView2dSession);
+}
+
+TEST_P(SurroundViewHidlTest, projectCameraPointsWithInvalidCameraId) {
+ ALOGD("SurroundViewHidlTest, projectCameraPointsWithInvalidCameraId");
+ sp<ISurroundView2dSession> surroundView2dSession;
+ mSurroundViewService->start2dSession(
+ [&surroundView2dSession](
+ const sp<ISurroundView2dSession>& session, SvResult result) {
+ ASSERT_EQ(result, SvResult::OK);
+ surroundView2dSession = session;
+ });
+
+ hidl_vec<hidl_string> cameraIds;
+ mSurroundViewService->getCameraIds([&cameraIds](
+ const hidl_vec<hidl_string>& camIds) {
+ cameraIds = camIds;
+ });
+
+ hidl_string invalidCameraId = "INVALID_CAMERA_ID";
+
+ // In case one of the camera id happens to be identical to
+ // the invalid camera id.
+ for (auto cameraId : cameraIds) {
+ ASSERT_NE(cameraId, invalidCameraId);
+ }
+
+ // Set one valid point
+ hidl_vec<Point2dInt> points2dCamera;
+ points2dCamera.resize(1);
+ points2dCamera[0].x = 0;
+ points2dCamera[0].y = 0;
+
+ surroundView2dSession->projectCameraPoints(
+ points2dCamera,
+ invalidCameraId,
+ [] (const hidl_vec<Point2dFloat>& outPoints) {
+ // No points are return due to invalid camera id
+ EXPECT_EQ(outPoints.size(), 0);
+ });
+
+ // Clean up
+ surroundView2dSession->stopStream();
+ mSurroundViewService->stop2dSession(surroundView2dSession);
+}
+
+TEST_P(SurroundViewHidlTest, startAndStop3dSession) {
+ ALOGD("SurroundViewHidlTest, startAndStop3dSession");
+ sp<ISurroundView3dSession> surroundView3dSession;
+ mSurroundViewService->start3dSession(
+ [&surroundView3dSession](
+ const sp<ISurroundView3dSession>& session, SvResult result) {
+ ASSERT_EQ(result, SvResult::OK);
+ surroundView3dSession = session;
+ });
+
+ SvResult result = mSurroundViewService->stop3dSession(surroundView3dSession);
+ EXPECT_EQ(result, SvResult::OK);
+}
+
+TEST_P(SurroundViewHidlTest, stopInvalid3dSession) {
+ ALOGD("SurroundViewHidlTest, stopInvalid3dSession");
+ sp<ISurroundView3dSession> surroundView3dSession;
+ SvResult result = mSurroundViewService->stop3dSession(surroundView3dSession);
+ EXPECT_NE(result, SvResult::OK);
+}
+
+TEST_P(SurroundViewHidlTest, startAndStop3dStream) {
+ ALOGD("SurroundViewHidlTest::startAndStop3dStream");
+ sp<ISurroundView3dSession> surroundView3dSession;
+ mSurroundViewService->start3dSession(
+ [&surroundView3dSession](
+ const sp<ISurroundView3dSession>& session, SvResult result) {
+ ASSERT_EQ(result, SvResult::OK);
+ surroundView3dSession = session;
+ });
+
+ std::vector<View3d> views(1);
+ SvResult setViewResult = surroundView3dSession->setViews(views);
+ EXPECT_EQ(setViewResult, SvResult::OK);
+
+ sp<SurroundViewServiceHandler> handler =
+ new SurroundViewServiceHandler(surroundView3dSession);
+
+ SvResult result = surroundView3dSession->startStream(handler);
+ EXPECT_EQ(result, SvResult::OK);
+
+ sleep(5);
+
+ EXPECT_TRUE(handler->checkEventReceived(SvEvent::STREAM_STARTED));
+ EXPECT_GT(handler->getReceiveFramesCount(), 0);
+
+ surroundView3dSession->stopStream();
+
+ sleep(1);
+ EXPECT_TRUE(handler->checkEventReceived(SvEvent::STREAM_STOPPED));
+
+ result = mSurroundViewService->stop3dSession(surroundView3dSession);
+ EXPECT_EQ(result, SvResult::OK);
+}
+
+TEST_P(SurroundViewHidlTest, start3dStreamWithoutReturningFrames) {
+ ALOGD("SurroundViewHidlTest::start3dStreamWithoutReturningFrames");
+ sp<ISurroundView3dSession> surroundView3dSession;
+ mSurroundViewService->start3dSession(
+ [&surroundView3dSession](
+ const sp<ISurroundView3dSession>& session, SvResult result) {
+ ASSERT_EQ(result, SvResult::OK);
+ surroundView3dSession = session;
+ });
+
+ std::vector<View3d> views(1);
+ SvResult setViewResult = surroundView3dSession->setViews(views);
+ EXPECT_EQ(setViewResult, SvResult::OK);
+
+ sp<SurroundViewServiceHandler> handler =
+ new SurroundViewServiceHandler(surroundView3dSession);
+ handler->setDoNotReturnFrames(true);
+
+ SvResult result = surroundView3dSession->startStream(handler);
+ EXPECT_EQ(result, SvResult::OK);
+
+ sleep(5);
+
+ EXPECT_TRUE(handler->checkEventReceived(SvEvent::STREAM_STARTED));
+ EXPECT_TRUE(handler->checkEventReceived(SvEvent::FRAME_DROPPED));
+ EXPECT_GT(handler->getReceiveFramesCount(), 0);
+
+ surroundView3dSession->stopStream();
+
+ sleep(1);
+ EXPECT_TRUE(handler->checkEventReceived(SvEvent::STREAM_STOPPED));
+
+ result = mSurroundViewService->stop3dSession(surroundView3dSession);
+ EXPECT_EQ(result, SvResult::OK);
+}
+
+TEST_P(SurroundViewHidlTest, duplicateStart3dStream) {
+ ALOGD("SurroundViewHidlTest, duplicateStart3dStream");
+ sp<ISurroundView3dSession> surroundView3dSession;
+ mSurroundViewService->start3dSession(
+ [&surroundView3dSession](
+ const sp<ISurroundView3dSession>& session, SvResult result) {
+ ASSERT_EQ(result, SvResult::OK);
+ surroundView3dSession = session;
+ });
+
+ std::vector<View3d> views(1);
+ SvResult setViewResult = surroundView3dSession->setViews(views);
+ EXPECT_EQ(setViewResult, SvResult::OK);
+
+ sp<SurroundViewServiceHandler> handler =
+ new SurroundViewServiceHandler(surroundView3dSession);
+
+ SvResult result = surroundView3dSession->startStream(handler);
+ EXPECT_EQ(result, SvResult::OK);
+
+ result = surroundView3dSession->startStream(handler);
+ EXPECT_NE(result, SvResult::OK);
+
+ surroundView3dSession->stopStream();
+ mSurroundViewService->stop3dSession(surroundView3dSession);
+}
+
+TEST_P(SurroundViewHidlTest, start3dStreamNoViewSetFail) {
+ ALOGD("SurroundViewHidlTest, start3dStreamNoViewSetFail");
+ sp<ISurroundView3dSession> surroundView3dSession;
+ mSurroundViewService->start3dSession(
+ [&surroundView3dSession](
+ const sp<ISurroundView3dSession>& session, SvResult result) {
+ ASSERT_EQ(result, SvResult::OK);
+ surroundView3dSession = session;
+ });
+
+ sp<SurroundViewServiceHandler> handler =
+ new SurroundViewServiceHandler(surroundView3dSession);
+
+ SvResult result = surroundView3dSession->startStream(handler);
+ EXPECT_EQ(result, SvResult::VIEW_NOT_SET);
+
+ mSurroundViewService->stop3dSession(surroundView3dSession);
+}
+
+TEST_P(SurroundViewHidlTest, validate3dSvFramesDesc) {
+ ALOGD("SurroundViewHidlTest, validate3dSvFramesDesc");
+ sp<ISurroundView3dSession> surroundView3dSession;
+ mSurroundViewService->start3dSession(
+ [&surroundView3dSession](
+ const sp<ISurroundView3dSession>& session, SvResult result) {
+ ASSERT_EQ(result, SvResult::OK);
+ surroundView3dSession = session;
+ });
+
+ sp<SurroundViewServiceHandler> handler =
+ new SurroundViewServiceHandler(surroundView3dSession);
+
+ std::vector<View3d> views(1);
+ views[0].viewId = 0;
+ SvResult setViewResult = surroundView3dSession->setViews(views);
+ EXPECT_EQ(setViewResult, SvResult::OK);
+
+ SvResult result = surroundView3dSession->startStream(handler);
+ EXPECT_EQ(result, SvResult::OK);
+
+ sleep(5);
+
+ EXPECT_GT(handler->getReceiveFramesCount(), 0);
+ EXPECT_TRUE(handler->areAllFramesValid());
+
+ // Validate 3d SvFramesDesc when only one view is set.
+ SvFramesDesc frames = handler->getLastReceivedFrames();
+ EXPECT_EQ(frames.svBuffers.size(), 1);
+ EXPECT_EQ(frames.svBuffers[0].viewId, 0);
+
+ views.resize(3);
+ views[0].viewId = 0;
+ views[1].viewId = 1;
+ views[2].viewId = 2;
+ setViewResult = surroundView3dSession->setViews(views);
+ EXPECT_EQ(setViewResult, SvResult::OK);
+
+ sleep(1);
+
+ // Validate 3d SvFramesDesc when multiple views are set.
+ EXPECT_TRUE(handler->areAllFramesValid());
+ frames = handler->getLastReceivedFrames();
+ EXPECT_EQ(frames.svBuffers.size(), 3);
+ EXPECT_EQ(frames.svBuffers[0].viewId, 0);
+ EXPECT_EQ(frames.svBuffers[1].viewId, 1);
+ EXPECT_EQ(frames.svBuffers[2].viewId, 2);
+ EXPECT_EQ(frames.svBuffers[0].hardwareBuffer.description[0],
+ frames.svBuffers[1].hardwareBuffer.description[0]);
+ EXPECT_EQ(frames.svBuffers[0].hardwareBuffer.description[1],
+ frames.svBuffers[1].hardwareBuffer.description[1]);
+ EXPECT_EQ(frames.svBuffers[1].hardwareBuffer.description[0],
+ frames.svBuffers[2].hardwareBuffer.description[0]);
+ EXPECT_EQ(frames.svBuffers[1].hardwareBuffer.description[1],
+ frames.svBuffers[2].hardwareBuffer.description[1]);
+
+ // Clean up
+ surroundView3dSession->stopStream();
+ result = mSurroundViewService->stop3dSession(surroundView3dSession);
+}
+
+TEST_P(SurroundViewHidlTest, set3dConfigResolution) {
+ ALOGD("SurroundViewHidlTest, set3dConfigResolution");
+ sp<ISurroundView3dSession> surroundView3dSession;
+ mSurroundViewService->start3dSession(
+ [&surroundView3dSession](
+ const sp<ISurroundView3dSession>& session, SvResult result) {
+ ASSERT_EQ(result, SvResult::OK);
+ surroundView3dSession = session;
+ });
+
+ sp<SurroundViewServiceHandler> handler =
+ new SurroundViewServiceHandler(surroundView3dSession);
+
+ std::vector<View3d> views(1);
+ views[0].viewId = 0;
+ SvResult setViewResult = surroundView3dSession->setViews(views);
+ EXPECT_EQ(setViewResult, SvResult::OK);
+ SvResult result = surroundView3dSession->startStream(handler);
+ EXPECT_EQ(result, SvResult::OK);
+
+ sleep(1);
+
+ // Change config
+ Sv3dConfig config;
+ config.width = 1920;
+ config.height = 1080;
+ config.carDetails = SvQuality::HIGH;
+ surroundView3dSession->set3dConfig(config);
+
+ sleep(1);
+
+ EXPECT_TRUE(handler->checkEventReceived(SvEvent::CONFIG_UPDATED));
+
+ // Check width has been changed but not the ratio
+ SvFramesDesc frames = handler->getLastReceivedFrames();
+ EXPECT_EQ(frames.svBuffers.size(), 1);
+ SvBuffer svBuffer3d = frames.svBuffers[0];
+ EXPECT_EQ(svBuffer3d.viewId, 0);
+ const AHardwareBuffer_Desc* pDesc =
+ reinterpret_cast<const AHardwareBuffer_Desc *>(&svBuffer3d.hardwareBuffer.description);
+ EXPECT_EQ(pDesc->width, config.width);
+ EXPECT_EQ(pDesc->height, config.height);
+
+ // Clean up
+ surroundView3dSession->stopStream();
+ mSurroundViewService->stop3dSession(surroundView3dSession);
+}
+
+TEST_P(SurroundViewHidlTest, set3dConfigCarDetails) {
+ ALOGD("SurroundViewHidlTest, set3dConfigCarDetails");
+ sp<ISurroundView3dSession> surroundView3dSession;
+ mSurroundViewService->start3dSession(
+ [&surroundView3dSession](
+ const sp<ISurroundView3dSession>& session, SvResult result) {
+ ASSERT_EQ(result, SvResult::OK);
+ surroundView3dSession = session;
+ });
+
+ sp<SurroundViewServiceHandler> handler =
+ new SurroundViewServiceHandler(surroundView3dSession);
+
+ std::vector<View3d> views(1);
+ views[0].viewId = 0;
+ SvResult setViewResult = surroundView3dSession->setViews(views);
+ EXPECT_EQ(setViewResult, SvResult::OK);
+ SvResult result = surroundView3dSession->startStream(handler);
+ EXPECT_EQ(result, SvResult::OK);
+
+ sleep(1);
+
+ // Get the width before config changed
+ int oldWidth, oldHeight;
+ SvFramesDesc frames = handler->getLastReceivedFrames();
+ EXPECT_EQ(frames.svBuffers.size(), 1);
+ SvBuffer svBuffer3d = frames.svBuffers[0];
+ const AHardwareBuffer_Desc* pDesc =
+ reinterpret_cast<const AHardwareBuffer_Desc *>(&svBuffer3d.hardwareBuffer.description);
+ oldWidth = pDesc->width;
+ oldHeight = pDesc->height;
+
+ // Change config
+ Sv3dConfig config;
+ config.width = oldWidth;
+ config.height = oldHeight;
+ config.carDetails = SvQuality::LOW;
+ surroundView3dSession->set3dConfig(config);
+
+ sleep(1);
+
+ EXPECT_TRUE(handler->checkEventReceived(SvEvent::CONFIG_UPDATED));
+
+ Sv3dConfig retConfig;
+ surroundView3dSession->get3dConfig([&retConfig] (Sv3dConfig config) {
+ retConfig.width = config.width;
+ retConfig.height = config.height;
+ retConfig.carDetails = config.carDetails;
+ });
+
+ // Check config blending has been changed but not the width
+ EXPECT_EQ(retConfig.carDetails, config.carDetails);
+ EXPECT_EQ(retConfig.width, oldWidth);
+ EXPECT_EQ(retConfig.height, oldHeight);
+
+ // Clean up
+ surroundView3dSession->stopStream();
+ mSurroundViewService->stop3dSession(surroundView3dSession);
+}
+
+std::pair<hidl_memory, sp<IMemory>> GetMappedSharedMemory(int bytesSize) {
+
+ const auto nullResult = std::make_pair(hidl_memory(), nullptr);
+
+ sp<IAllocator> ashmemAllocator = IAllocator::getService("ashmem");
+ if (ashmemAllocator.get() == nullptr) {
+ ALOGE("SurroundViewHidlTest getService ashmem failed");
+ return nullResult;
+ }
+
+ // Allocate shared memory.
+ hidl_memory hidlMemory;
+ bool allocateSuccess = false;
+ Return<void> result = ashmemAllocator->allocate(bytesSize,
+ [&](bool success, const hidl_memory& hidlMem) {
+ if (!success) {
+ return;
+ }
+ allocateSuccess = success;
+ hidlMemory = hidlMem;
+ });
+
+ // Check result of allocated memory.
+ if (!result.isOk() || !allocateSuccess) {
+ ALOGE("SurroundViewHidlTest allocate shared memory failed");
+ return nullResult;
+ }
+
+ // Map shared memory.
+ sp<IMemory> pIMemory = mapMemory(hidlMemory);
+ if (pIMemory.get() == nullptr) {
+ ALOGE("SurroundViewHidlTest map shared memory failed");
+ return nullResult;
+ }
+
+ return std::make_pair(hidlMemory, pIMemory);
+}
+
+void SetIndexOfOverlaysMemory(
+ const std::vector<OverlayMemoryDesc>& overlaysMemDesc,
+ sp<IMemory> pIMemory, int indexPosition, uint16_t indexValue) {
+
+ // Count the number of vertices until the index.
+ int totalVerticesCount = 0;
+ for (int i = 0; i < indexPosition; i++) {
+ totalVerticesCount += overlaysMemDesc[i].verticesCount;
+ }
+
+ const int indexBytePosition = (indexPosition * kIdByteSize) +
+ (kVertexByteSize * totalVerticesCount);
+
+ uint8_t* pSharedMemoryData = (uint8_t*)((void*)pIMemory->getPointer());
+ pSharedMemoryData += indexBytePosition;
+ uint16_t* pIndex16bit = (uint16_t*)pSharedMemoryData;
+
+ ALOGD("Setting index at pos %d", indexBytePosition);
+
+ // Modify shared memory.
+ pIMemory->update();
+ *pIndex16bit = indexValue;
+ pIMemory->commit();
+}
+
+std::pair<OverlaysData, sp<IMemory>> GetSampleOverlaysData() {
+ OverlaysData overlaysData;
+ overlaysData.overlaysMemoryDesc.resize(2);
+
+ int sharedMemBytesSize = 0;
+ OverlayMemoryDesc overlayMemDesc1, overlayMemDesc2;
+ overlayMemDesc1.id = 0;
+ overlayMemDesc1.verticesCount = 6;
+ overlayMemDesc1.overlayPrimitive = OverlayPrimitive::TRIANGLES;
+ overlaysData.overlaysMemoryDesc[0] = overlayMemDesc1;
+ sharedMemBytesSize += kIdByteSize +
+ kVertexByteSize * overlayMemDesc1.verticesCount;
+
+ overlayMemDesc2.id = 1;
+ overlayMemDesc2.verticesCount = 4;
+ overlayMemDesc2.overlayPrimitive = OverlayPrimitive::TRIANGLES_STRIP;
+ overlaysData.overlaysMemoryDesc[1] = overlayMemDesc2;
+ sharedMemBytesSize += kIdByteSize +
+ kVertexByteSize * overlayMemDesc2.verticesCount;
+
+ std::pair<hidl_memory, sp<IMemory>> sharedMem =
+ GetMappedSharedMemory(sharedMemBytesSize);
+ sp<IMemory> pIMemory = sharedMem.second;
+ if (pIMemory.get() == nullptr) {
+ return std::make_pair(OverlaysData(), nullptr);
+ }
+
+ // Get pointer to shared memory data and set all bytes to 0.
+ uint8_t* pSharedMemoryData = (uint8_t*)((void*)pIMemory->getPointer());
+ pIMemory->update();
+ memset(pSharedMemoryData, 0, sharedMemBytesSize);
+ pIMemory->commit();
+
+ std::vector<OverlayMemoryDesc> overlaysDesc = {overlayMemDesc1,
+ overlayMemDesc2};
+
+ // Set indexes in shared memory.
+ SetIndexOfOverlaysMemory(overlaysDesc, pIMemory, 0, overlayMemDesc1.id);
+ SetIndexOfOverlaysMemory(overlaysDesc, pIMemory, 1, overlayMemDesc2.id);
+
+ overlaysData.overlaysMemoryDesc = overlaysDesc;
+ overlaysData.overlaysMemory = sharedMem.first;
+
+ return std::make_pair(overlaysData, pIMemory);
+}
+
+TEST_P(SurroundViewHidlTest, updateOverlaysSuccess) {
+ ALOGD("SurroundViewHidlTest, updateOverlaysSuccess");
+
+ sp<ISurroundView3dSession> surroundView3dSession;
+ mSurroundViewService->start3dSession(
+ [&surroundView3dSession](
+ const sp<ISurroundView3dSession>& session, SvResult result) {
+ ASSERT_EQ(result, SvResult::OK);
+ surroundView3dSession = session;
+ });
+
+ std::pair<OverlaysData, sp<IMemory>> overlaysData = GetSampleOverlaysData();
+ ASSERT_NE(overlaysData.second, nullptr);
+
+ SvResult result = surroundView3dSession->updateOverlays(overlaysData.first);
+ EXPECT_EQ(result, SvResult::OK);
+
+ mSurroundViewService->stop3dSession(surroundView3dSession);
+}
+
+TEST_P(SurroundViewHidlTest, overlaysDataMismatchIdFail) {
+ ALOGD("SurroundViewHidlTest, overlaysDataMismatchIdFail");
+
+ sp<ISurroundView3dSession> surroundView3dSession;
+ mSurroundViewService->start3dSession(
+ [&surroundView3dSession](
+ const sp<ISurroundView3dSession>& session, SvResult result) {
+ ASSERT_EQ(result, SvResult::OK);
+ surroundView3dSession = session;
+ });
+
+ std::pair<OverlaysData, sp<IMemory>> overlaysDataMismatchId
+ = GetSampleOverlaysData();
+ ASSERT_NE(overlaysDataMismatchId.second, nullptr);
+
+ // Set id of second overlay in shared memory to 2 (expected is 1).
+ auto& overlaysDesc = overlaysDataMismatchId.first.overlaysMemoryDesc;
+ auto& pIMemory = overlaysDataMismatchId.second;
+ SetIndexOfOverlaysMemory(overlaysDesc, pIMemory, 1, 2);
+
+ SvResult result = surroundView3dSession->updateOverlays(
+ overlaysDataMismatchId.first);
+ EXPECT_EQ(result, SvResult::INVALID_ARG);
+
+ mSurroundViewService->stop3dSession(surroundView3dSession);
+}
+
+TEST_P(SurroundViewHidlTest, overlaysDataNullMemoryFail) {
+ ALOGD("SurroundViewHidlTest, overlaysDataNullMemoryFail");
+
+ sp<ISurroundView3dSession> surroundView3dSession;
+ mSurroundViewService->start3dSession(
+ [&surroundView3dSession](
+ const sp<ISurroundView3dSession>& session, SvResult result) {
+ ASSERT_EQ(result, SvResult::OK);
+ surroundView3dSession = session;
+ });
+
+ std::pair<OverlaysData, sp<IMemory>> overlaysDataNullMemory
+ = GetSampleOverlaysData();
+
+ // Set shared memory to null.
+ overlaysDataNullMemory.first.overlaysMemory = hidl_memory();
+
+ SvResult result = surroundView3dSession->updateOverlays(
+ overlaysDataNullMemory.first);
+ EXPECT_EQ(result, SvResult::INVALID_ARG);
+
+ mSurroundViewService->stop3dSession(surroundView3dSession);
+}
+
+TEST_P(SurroundViewHidlTest, overlaysDataLessThan3VerticesFail) {
+ ALOGD("SurroundViewHidlTest, overlaysDataLessThan3VerticesFail");
+
+ sp<ISurroundView3dSession> surroundView3dSession;
+ mSurroundViewService->start3dSession(
+ [&surroundView3dSession](
+ const sp<ISurroundView3dSession>& session, SvResult result) {
+ ASSERT_EQ(result, SvResult::OK);
+ surroundView3dSession = session;
+ });
+
+ std::pair<OverlaysData, sp<IMemory>> overlaysData2Vertices
+ = GetSampleOverlaysData();
+
+ // Set vertices count of second overlay to 2.
+ overlaysData2Vertices.first.overlaysMemoryDesc[1].verticesCount = 2;
+
+ SvResult result = surroundView3dSession->updateOverlays(
+ overlaysData2Vertices.first);
+ EXPECT_EQ(result, SvResult::INVALID_ARG);
+
+ mSurroundViewService->stop3dSession(surroundView3dSession);
+}
+
+TEST_P(SurroundViewHidlTest, overlaysDataVerticesCountFail) {
+ ALOGD("SurroundViewHidlTest, overlaysDataVerticesNotMultipleOf3Fail");
+
+ sp<ISurroundView3dSession> surroundView3dSession;
+ mSurroundViewService->start3dSession(
+ [&surroundView3dSession](
+ const sp<ISurroundView3dSession>& session, SvResult result) {
+ ASSERT_EQ(result, SvResult::OK);
+ surroundView3dSession = session;
+ });
+
+ OverlaysData overlaysData;
+ overlaysData.overlaysMemoryDesc.resize(1);
+
+ OverlayMemoryDesc overlayMemDesc1;
+ overlayMemDesc1.id = 0;
+ overlayMemDesc1.verticesCount = 4; // Invalid count for TRIANGLES primitive.
+ overlayMemDesc1.overlayPrimitive = OverlayPrimitive::TRIANGLES;
+ overlaysData.overlaysMemoryDesc[0] = overlayMemDesc1;
+
+ const int sharedMemBytesSize =
+ 2 + sizeof(float) * overlayMemDesc1.verticesCount;
+ auto sharedMem = GetMappedSharedMemory(sharedMemBytesSize);
+
+ // Set index in shared memory.
+ auto& overlaysDesc = overlaysData.overlaysMemoryDesc;
+ auto& pIMemory = sharedMem.second;
+ SetIndexOfOverlaysMemory(overlaysDesc, pIMemory, 0, overlayMemDesc1.id);
+
+ SvResult result = surroundView3dSession->updateOverlays(overlaysData);
+ EXPECT_EQ(result, SvResult::INVALID_ARG);
+
+ mSurroundViewService->stop3dSession(surroundView3dSession);
+}
+
+TEST_P(SurroundViewHidlTest, overlaysDataSameIdFail) {
+ ALOGD("SurroundViewHidlTest, overlaysDataSameIdFail");
+
+ sp<ISurroundView3dSession> surroundView3dSession;
+ mSurroundViewService->start3dSession(
+ [&surroundView3dSession](
+ const sp<ISurroundView3dSession>& session, SvResult result) {
+ ASSERT_EQ(result, SvResult::OK);
+ surroundView3dSession = session;
+ });
+
+ std::pair<OverlaysData, sp<IMemory>> overlaysDataSameId
+ = GetSampleOverlaysData();
+ ASSERT_NE(overlaysDataSameId.second, nullptr);
+
+ // Set id of second overlay as id of first.
+ auto& overlaysDesc = overlaysDataSameId.first.overlaysMemoryDesc;
+ auto& pIMemory = overlaysDataSameId.second;
+ SetIndexOfOverlaysMemory(overlaysDesc, pIMemory, 1, overlaysDesc[0].id);
+
+ SvResult result = surroundView3dSession->updateOverlays(
+ overlaysDataSameId.first);
+ EXPECT_EQ(result, SvResult::INVALID_ARG);
+
+ mSurroundViewService->stop3dSession(surroundView3dSession);
+}
+
+TEST_P(SurroundViewHidlTest, projectPointsIncorrectCameraIdFail) {
+ ALOGD("SurroundViewHidlTest, projectPointsIncorrectCameraIdFail");
+
+ hidl_vec<hidl_string> cameraIds;
+ mSurroundViewService->getCameraIds([&cameraIds](
+ const hidl_vec<hidl_string>& camIds) {
+ cameraIds = camIds;
+ });
+ EXPECT_GT(cameraIds.size(), 0);
+
+ sp<ISurroundView3dSession> surroundView3dSession;
+ mSurroundViewService->start3dSession(
+ [&surroundView3dSession](
+ const sp<ISurroundView3dSession>& session, SvResult result) {
+ ASSERT_EQ(result, SvResult::OK);
+ surroundView3dSession = session;
+ });
+
+ Point2dInt cameraPoint;
+ cameraPoint.x = 0;
+ cameraPoint.y = 0;
+ std::vector<Point2dInt> cameraPoints = {cameraPoint};
+
+ hidl_string invalidCameraId = "INVALID_CAMERA_ID";
+
+ std::vector<Point3dFloat> points3d;
+ surroundView3dSession->projectCameraPointsTo3dSurface(
+ cameraPoints, invalidCameraId,
+ [&points3d](const hidl_vec<Point3dFloat>& points3dproj) {
+ points3d = points3dproj;
+ });
+
+ EXPECT_TRUE(points3d.empty());
+
+ mSurroundViewService->stop3dSession(surroundView3dSession);
+}
+
+TEST_P(SurroundViewHidlTest, projectPointsInvalidPointsFail) {
+ ALOGD("SurroundViewHidlTest, projectPointsInvalidPointsFail");
+
+ hidl_vec<hidl_string> cameraIds;
+ mSurroundViewService->getCameraIds([&cameraIds](
+ const hidl_vec<hidl_string>& camIds) {
+ cameraIds = camIds;
+ });
+
+ EXPECT_GT(cameraIds.size(), 0);
+
+ sp<ISurroundView3dSession> surroundView3dSession;
+ mSurroundViewService->start3dSession(
+ [&surroundView3dSession](
+ const sp<ISurroundView3dSession>& session, SvResult result) {
+ ASSERT_EQ(result, SvResult::OK);
+ surroundView3dSession = session;
+ });
+
+ sp<SurroundViewServiceHandler> handler =
+ new SurroundViewServiceHandler(surroundView3dSession);
+
+ std::vector<View3d> views(1);
+ views[0].viewId = 0;
+ SvResult setViewResult = surroundView3dSession->setViews(views);
+ EXPECT_EQ(setViewResult, SvResult::OK);
+ SvResult result = surroundView3dSession->startStream(handler);
+ EXPECT_EQ(result, SvResult::OK);
+
+ sleep(1);
+
+ // Get the width and height of the frame
+ int width, height;
+ SvFramesDesc frames = handler->getLastReceivedFrames();
+ EXPECT_EQ(frames.svBuffers.size(), 1);
+ SvBuffer svBuffer2d = frames.svBuffers[0];
+ const AHardwareBuffer_Desc* pDesc =
+ reinterpret_cast<const AHardwareBuffer_Desc *>(&svBuffer2d.hardwareBuffer.description);
+ width = pDesc->width;
+ height = pDesc->height;
+
+ Point2dInt cameraPoint;
+ cameraPoint.x = width * 2;
+ cameraPoint.y = height * 2;
+ std::vector<Point2dInt> cameraPoints = {cameraPoint};
+
+ std::vector<Point3dFloat> points3d;
+ surroundView3dSession->projectCameraPointsTo3dSurface(
+ cameraPoints, cameraIds[0],
+ [&points3d](const hidl_vec<Point3dFloat>& points3dproj) {
+ points3d = points3dproj;
+ });
+
+ EXPECT_FALSE(points3d[0].isValid);
+
+ surroundView3dSession->stopStream();
+ mSurroundViewService->stop3dSession(surroundView3dSession);
+}
+
+INSTANTIATE_TEST_SUITE_P(
+ PerInstance,
+ SurroundViewHidlTest,
+ testing::ValuesIn(
+ android::hardware::getAllHalInstanceNames(ISurroundViewService::descriptor)
+ ),
+ android::hardware::PrintInstanceNameToString
+);
diff --git a/automotive/vehicle/2.0/default/impl/vhal_v2_0/DefaultConfig.h b/automotive/vehicle/2.0/default/impl/vhal_v2_0/DefaultConfig.h
index 785f0e0..4b94800 100644
--- a/automotive/vehicle/2.0/default/impl/vhal_v2_0/DefaultConfig.h
+++ b/automotive/vehicle/2.0/default/impl/vhal_v2_0/DefaultConfig.h
@@ -70,6 +70,7 @@
(int)(0x104 | VehiclePropertyGroup::VENDOR | VehiclePropertyType::STRING | VehicleArea::GLOBAL);
constexpr int FUEL_DOOR_REAR_LEFT = (int)PortLocationType::REAR_LEFT;
constexpr int CHARGE_PORT_FRONT_LEFT = (int)PortLocationType::FRONT_LEFT;
+constexpr int CHARGE_PORT_REAR_LEFT = (int)PortLocationType::REAR_LEFT;
constexpr int LIGHT_STATE_ON = (int)VehicleLightState::ON;
constexpr int LIGHT_SWITCH_AUTO = (int)VehicleLightSwitch::AUTOMATIC;
constexpr int WHEEL_FRONT_LEFT = (int)VehicleAreaWheel::LEFT_FRONT;
@@ -249,6 +250,14 @@
{.config =
{
+ .prop = toInt(VehicleProperty::INFO_MULTI_EV_PORT_LOCATIONS),
+ .access = VehiclePropertyAccess::READ,
+ .changeMode = VehiclePropertyChangeMode::STATIC,
+ },
+ .initialValue = {.int32Values = {CHARGE_PORT_FRONT_LEFT, CHARGE_PORT_REAR_LEFT}}},
+
+ {.config =
+ {
.prop = toInt(VehicleProperty::INFO_MAKE),
.access = VehiclePropertyAccess::READ,
.changeMode = VehiclePropertyChangeMode::STATIC,
@@ -457,6 +466,14 @@
},
.initialValue = {.int32Values = {0, 0, 0}}},
+ {.config =
+ {
+ .prop = toInt(VehicleProperty::HW_ROTARY_INPUT),
+ .access = VehiclePropertyAccess::READ,
+ .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
+ },
+ .initialValue = {.int32Values = {0, 0, 0}}},
+
{.config = {.prop = toInt(VehicleProperty::HVAC_POWER_ON),
.access = VehiclePropertyAccess::READ_WRITE,
.changeMode = VehiclePropertyChangeMode::ON_CHANGE,
diff --git a/automotive/vehicle/2.0/types.hal b/automotive/vehicle/2.0/types.hal
index cbd9e28..23f9135 100644
--- a/automotive/vehicle/2.0/types.hal
+++ b/automotive/vehicle/2.0/types.hal
@@ -320,6 +320,25 @@
| VehicleArea:GLOBAL),
/**
+ * Multiple EV port locations
+ *
+ * Implement this property if the vehicle has multiple EV ports.
+ * Port locations are defined in PortLocationType.
+ * For example, a car has one port in front left and one port in rear left:
+ * int32Values[0] = PortLocationType::FRONT_LEFT
+ * int32Values[0] = PortLocationType::REAR_LEFT
+ *
+ * @change_mode VehiclePropertyChangeMode:STATIC
+ * @access VehiclePropertyAccess:READ
+ * @data_enum PortLocationType
+ */
+ INFO_MULTI_EV_PORT_LOCATIONS = (
+ 0x010C
+ | VehiclePropertyGroup:SYSTEM
+ | VehiclePropertyType:INT32_VEC
+ | VehicleArea:GLOBAL),
+
+ /**
* Current odometer value of the vehicle
*
* @change_mode VehiclePropertyChangeMode:CONTINUOUS
@@ -1413,6 +1432,33 @@
| VehiclePropertyType:INT32_VEC
| VehicleArea:GLOBAL),
+ /**
+ * Property to feed H/W rotary events to android
+ *
+ * int32Values[0] : RotaryInputType identifying which rotary knob rotated
+ * int32Values[1] : number of detents (clicks), positive for clockwise,
+ * negative for counterclockwise
+ * int32Values[2] : target display defined in VehicleDisplay. Events not
+ * tied to specific display must be sent to
+ * VehicleDisplay#MAIN.
+ * int32values[3 .. 3 + abs(number of detents) - 2]:
+ * nanosecond deltas between pairs of consecutive detents,
+ * if the number of detents is > 1 or < -1
+ *
+ * VehiclePropValue.timestamp: when the rotation occurred. If the number of
+ * detents is > 1 or < -1, this is when the
+ * first detent of rotation occurred.
+ *
+ * @change_mode VehiclePropertyChangeMode:ON_CHANGE
+ * @data_enum RotaryInputType
+ * @access VehiclePropertyAccess:READ
+ */
+ HW_ROTARY_INPUT = (
+ 0x0A20
+ | VehiclePropertyGroup:SYSTEM
+ | VehiclePropertyType:INT32_VEC
+ | VehicleArea:GLOBAL),
+
/***************************************************************************
* Most Car Cabin properties have both a POSition and MOVE parameter. These
* are used to control the various movements for seats, doors, and windows
@@ -4651,3 +4697,18 @@
UserIdentificationAssociationSetValue value;
};
+
+/**
+ * A rotary control which can rotate without limits. These controls use HW_ROTARY_INPUT to report
+ * relative clockwise or counterclockwise motion. They have no absolute position.
+ */
+enum RotaryInputType : int32_t {
+ /**
+ * Main rotary control, typically in the center console, used to navigate the user interface.
+ */
+ ROTARY_INPUT_TYPE_SYSTEM_NAVIGATION = 0,
+
+ /** Volume control for adjusting audio volume. */
+ ROTARY_INPUT_TYPE_AUDIO_VOLUME = 1,
+};
+
diff --git a/compatibility_matrices/compatibility_matrix.current.xml b/compatibility_matrices/compatibility_matrix.current.xml
index f1db89d..de1ee84 100644
--- a/compatibility_matrices/compatibility_matrix.current.xml
+++ b/compatibility_matrices/compatibility_matrix.current.xml
@@ -56,6 +56,14 @@
</interface>
</hal>
<hal format="hidl" optional="true">
+ <name>android.hardware.automotive.sv</name>
+ <version>1.0</version>
+ <interface>
+ <name>ISurroundView</name>
+ <instance>default</instance>
+ </interface>
+ </hal>
+ <hal format="hidl" optional="true">
<name>android.hardware.automotive.vehicle</name>
<version>2.0</version>
<interface>
diff --git a/confirmationui/1.0/vts/functional/VtsHalConfirmationUIV1_0TargetTest.cpp b/confirmationui/1.0/vts/functional/VtsHalConfirmationUIV1_0TargetTest.cpp
index 278d1f4..fb01ad0 100644
--- a/confirmationui/1.0/vts/functional/VtsHalConfirmationUIV1_0TargetTest.cpp
+++ b/confirmationui/1.0/vts/functional/VtsHalConfirmationUIV1_0TargetTest.cpp
@@ -336,7 +336,7 @@
ASSERT_EQ(0U, result.args->formattedMessage_.size());
}
-// Simulates the framework candelling an ongoing prompt
+// Simulates the framework cancelling an ongoing prompt
TEST_F(ConfirmationUIHidlTest, AbortTest) {
static constexpr char test_prompt[] = "Me first, gimme gimme!";
static constexpr uint8_t test_extra[] = {0x1, 0x2, 0x3};
@@ -354,6 +354,92 @@
ASSERT_EQ(0U, result.args->formattedMessage_.size());
}
+// Tests if the confirmation dialog can successfully render 100 'W' characters as required by
+// the design guidelines.
+TEST_F(ConfirmationUIHidlTest, PortableMessageTest1) {
+ static constexpr char test_prompt[] =
+ "WWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW"
+ "WWWWWWWWWWWWWW";
+ static constexpr uint8_t test_extra[] = {0x1, 0x2, 0x3};
+ sp<ConfirmationTestCallback> conf_cb = new ConfirmationTestCallback;
+ hidl_string prompt_text(test_prompt);
+ hidl_vec<uint8_t> extra(test_extra, test_extra + 3);
+ ASSERT_HAL_CALL(ResponseCode::OK,
+ confirmator().promptUserConfirmation(conf_cb, prompt_text, extra, "en", {}));
+
+ confirmator().abort();
+
+ auto result = conf_cb->WaitForCallback();
+ ASSERT_EQ(ResponseCode::Aborted, result.args->error_);
+ ASSERT_EQ(0U, result.args->confirmationToken_.size());
+ ASSERT_EQ(0U, result.args->formattedMessage_.size());
+}
+
+// Tests if the confirmation dialog can successfully render 100 'W' characters as required by
+// the design guidelines in magnified mode.
+TEST_F(ConfirmationUIHidlTest, PortableMessageTest1Magnified) {
+ static constexpr char test_prompt[] =
+ "WWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW"
+ "WWWWWWWWWWWWWW";
+ static constexpr uint8_t test_extra[] = {0x1, 0x2, 0x3};
+ sp<ConfirmationTestCallback> conf_cb = new ConfirmationTestCallback;
+ hidl_string prompt_text(test_prompt);
+ hidl_vec<uint8_t> extra(test_extra, test_extra + 3);
+ ASSERT_HAL_CALL(ResponseCode::OK,
+ confirmator().promptUserConfirmation(conf_cb, prompt_text, extra, "en",
+ {UIOption::AccessibilityMagnified}));
+
+ confirmator().abort();
+
+ auto result = conf_cb->WaitForCallback();
+ ASSERT_EQ(ResponseCode::Aborted, result.args->error_);
+ ASSERT_EQ(0U, result.args->confirmationToken_.size());
+ ASSERT_EQ(0U, result.args->formattedMessage_.size());
+}
+
+// Tests if the confirmation dialog can successfully render 8 groups of 12 'W' characters as
+// required by the design guidelines.
+TEST_F(ConfirmationUIHidlTest, PortableMessageTest2) {
+ static constexpr char test_prompt[] =
+ "WWWWWWWWWWWW WWWWWWWWWWWW WWWWWWWWWWWW WWWWWWWWWWWW WWWWWWWWWWWW WWWWWWWWWWWW "
+ "WWWWWWWWWWWW WWWWWWWWWWWW";
+ static constexpr uint8_t test_extra[] = {0x1, 0x2, 0x3};
+ sp<ConfirmationTestCallback> conf_cb = new ConfirmationTestCallback;
+ hidl_string prompt_text(test_prompt);
+ hidl_vec<uint8_t> extra(test_extra, test_extra + 3);
+ ASSERT_HAL_CALL(ResponseCode::OK,
+ confirmator().promptUserConfirmation(conf_cb, prompt_text, extra, "en", {}));
+
+ confirmator().abort();
+
+ auto result = conf_cb->WaitForCallback();
+ ASSERT_EQ(ResponseCode::Aborted, result.args->error_);
+ ASSERT_EQ(0U, result.args->confirmationToken_.size());
+ ASSERT_EQ(0U, result.args->formattedMessage_.size());
+}
+
+// Tests if the confirmation dialog can successfully render 8 groups of 12 'W' characters as
+// required by the design guidelines in magnified mode.
+TEST_F(ConfirmationUIHidlTest, PortableMessageTest2Magnified) {
+ static constexpr char test_prompt[] =
+ "WWWWWWWWWWWW WWWWWWWWWWWW WWWWWWWWWWWW WWWWWWWWWWWW WWWWWWWWWWWW WWWWWWWWWWWW "
+ "WWWWWWWWWWWW WWWWWWWWWWWW";
+ static constexpr uint8_t test_extra[] = {0x1, 0x2, 0x3};
+ sp<ConfirmationTestCallback> conf_cb = new ConfirmationTestCallback;
+ hidl_string prompt_text(test_prompt);
+ hidl_vec<uint8_t> extra(test_extra, test_extra + 3);
+ ASSERT_HAL_CALL(ResponseCode::OK,
+ confirmator().promptUserConfirmation(conf_cb, prompt_text, extra, "en",
+ {UIOption::AccessibilityMagnified}));
+
+ confirmator().abort();
+
+ auto result = conf_cb->WaitForCallback();
+ ASSERT_EQ(ResponseCode::Aborted, result.args->error_);
+ ASSERT_EQ(0U, result.args->confirmationToken_.size());
+ ASSERT_EQ(0U, result.args->formattedMessage_.size());
+}
+
// Passing malformed UTF-8 to the confirmation UI
// This test passes a string that ends in the middle of a multibyte character
TEST_F(ConfirmationUIHidlTest, MalformedUTF8Test1) {
diff --git a/current.txt b/current.txt
index 97d20ab..ec9f000 100644
--- a/current.txt
+++ b/current.txt
@@ -679,7 +679,7 @@
6e904be0ddca5ae1de8eba020e6c38ed935ea7d80cd08f47787f137a0ca58555 android.hardware.neuralnetworks@1.3::IFencedExecutionCallback
2b0b10d2ea7a18a4048cd0eb83d35c19a817aeee95f65807fc31f4ef21381397 android.hardware.neuralnetworks@1.3::IPreparedModel
eee3430cc86c97c7b407495863d8fb61da6f1a64b7721e77b9b4909b11b174e9 android.hardware.neuralnetworks@1.3::IPreparedModelCallback
-dd39887aa4fb60ce60ea9cc043edeadbbae6e922d09d3946311b0b410024ae14 android.hardware.neuralnetworks@1.3::types
+c9320b04ec302624985180a02d591bea5e435601fc411a6cabb58878e4e1ad68 android.hardware.neuralnetworks@1.3::types
3e01d4446cd69fd1c48f8572efd97487bc179564b32bd795800b97bbe10be37b android.hardware.wifi@1.4::IWifi
c67aaf26a7a40d14ea61e70e20afacbd0bb906df1704d585ac8599fbb69dd44b android.hardware.wifi.hostapd@1.2::IHostapd
2b5a7ea572b736030c64a3b4043af244425477c4672301780fe15aba5ed393d9 android.hardware.wifi.hostapd@1.2::types
diff --git a/neuralnetworks/1.3/types.hal b/neuralnetworks/1.3/types.hal
index 08d8e6b..daaf22e 100644
--- a/neuralnetworks/1.3/types.hal
+++ b/neuralnetworks/1.3/types.hal
@@ -1584,6 +1584,17 @@
* * 3: An optional {@link OperandType::BOOL} scalar, default to false.
* Set to true to specify NCHW data layout for input0 and output0.
* Available since HAL version 1.2.
+ * * 4: Align corners. An optional {@link OperandType::BOOL}
+ * scalar, default to false. If True, the centers of the 4 corner
+ * pixels of the input and output tensors are aligned, preserving the
+ * values at the corner pixels.
+ * Available since HAL version 1.3.
+ * * 5: Half pixel centers. An optional {@link OperandType::BOOL}
+ * scalar, default to false. If True, the pixel centers are assumed to
+ * be at (0.5, 0.5). This is the default behavior of image.resize in
+ * TF 2.0. If this parameter is True, then align_corners parameter
+ * must be False.
+ * Available since HAL version 1.3.
*
* Inputs (resizing by scale, since HAL version 1.2):
* * 0: A 4-D tensor, of shape [batches, height, width, depth], specifying
@@ -1602,6 +1613,17 @@
* {@link OperandType::FLOAT32} otherwise.
* * 3: An optional {@link OperandType::BOOL} scalar, default to false.
* Set to true to specify NCHW data layout for input0 and output0.
+ * * 4: Align corners. An optional {@link OperandType::BOOL}
+ * scalar, default to false. If True, the centers of the 4 corner
+ * pixels of the input and output tensors are aligned, preserving the
+ * values at the corner pixels.
+ * Available since HAL version 1.3.
+ * * 5: Half pixel centers. An optional {@link OperandType::BOOL}
+ * scalar, default to false. If True, the pixel centers are assumed to
+ * be at (0.5, 0.5). This is the default behavior of image.resize in
+ * TF 2.0. If this parameter is True, then align_corners parameter
+ * must be False.
+ * Available since HAL version 1.3.
*
* Outputs:
* * 0: The output 4-D tensor, of shape
@@ -4870,6 +4892,17 @@
* height of the output tensor.
* * 3: An {@link OperandType::BOOL} scalar, default to false.
* Set to true to specify NCHW data layout for input0 and output0.
+ * * 4: Align corners. An optional {@link OperandType::BOOL}
+ * scalar, default to false. If True, the centers of the 4 corner
+ * pixels of the input and output tensors are aligned, preserving the
+ * values at the corner pixels.
+ * Available since HAL version 1.3.
+ * * 5: Half pixel centers. An optional {@link OperandType::BOOL}
+ * scalar, default to false. If True, the pixel centers are assumed to
+ * be at (0.5, 0.5). This is the default behavior of image.resize in
+ * TF 2.0. If this parameter is True, then align_corners parameter
+ * must be False.
+ * Available since HAL version 1.3.
*
* Inputs (resizing by scale):
* * 0: A 4-D tensor, of shape [batches, height, width, depth], specifying
@@ -4888,6 +4921,17 @@
* {@link OperandType::FLOAT32} otherwise.
* * 3: An {@link OperandType::BOOL} scalar, default to false.
* Set to true to specify NCHW data layout for input0 and output0.
+ * * 4: Align corners. An optional {@link OperandType::BOOL}
+ * scalar, default to false. If True, the centers of the 4 corner
+ * pixels of the input and output tensors are aligned, preserving the
+ * values at the corner pixels.
+ * Available since HAL version 1.3.
+ * * 5: Half pixel centers. An optional {@link OperandType::BOOL}
+ * scalar, default to false. If True, the pixel centers are assumed to
+ * be at (0.5, 0.5). This is the default behavior of image.resize in
+ * TF 2.0. If this parameter is True, then align_corners parameter
+ * must be False.
+ * Available since HAL version 1.3.
*
* Outputs:
* * 0: The output 4-D tensor, of shape
diff --git a/neuralnetworks/1.3/vts/functional/ValidateModel.cpp b/neuralnetworks/1.3/vts/functional/ValidateModel.cpp
index 8f2d4b7..7da2da9 100644
--- a/neuralnetworks/1.3/vts/functional/ValidateModel.cpp
+++ b/neuralnetworks/1.3/vts/functional/ValidateModel.cpp
@@ -578,6 +578,8 @@
// - CONV_2D, DEPTHWISE_CONV_2D, MAX_POOL_2D, AVERAGE_POOL_2D, L2_POOL_2D, RESIZE_BILINEAR,
// SPACE_TO_DEPTH, SPACE_TO_DEPTH, SPACE_TO_BATCH_ND, BATCH_TO_SPACE_ND can have an optional
// layout parameter.
+ // RESIZE_BILINEAR and RESIZE_NEAREST_NEIGHBOR can have optional
+ // align_corners and half_pixel_centers parameters.
// - L2_NORMALIZATION, LOCAL_RESPONSE_NORMALIZATION, SOFTMAX can have an optional axis
// parameter.
switch (op.type) {
@@ -600,7 +602,12 @@
}
} break;
case OperationType::RESIZE_BILINEAR: {
- if (op.inputs.size() == 4 && input == 3) {
+ if (op.inputs.size() >= 4 && input >= 3) {
+ return true;
+ }
+ } break;
+ case OperationType::RESIZE_NEAREST_NEIGHBOR: {
+ if (op.inputs.size() >= 5 && input >= 3) {
return true;
}
} break;
@@ -686,7 +693,9 @@
// parameter.
if ((op.type == OperationType::L2_NORMALIZATION && op.inputs.size() == 1) ||
(op.type == OperationType::LOCAL_RESPONSE_NORMALIZATION && op.inputs.size() == 5) ||
- (op.type == OperationType::SOFTMAX && op.inputs.size() == 2)) {
+ (op.type == OperationType::SOFTMAX && op.inputs.size() == 2) ||
+ (op.type == OperationType::RESIZE_BILINEAR && op.inputs.size() < 6) ||
+ (op.type == OperationType::RESIZE_NEAREST_NEIGHBOR && op.inputs.size() < 6)) {
return true;
}
return false;
diff --git a/wifi/1.4/default/wifi_legacy_hal.cpp b/wifi/1.4/default/wifi_legacy_hal.cpp
index a040c89..f596195 100644
--- a/wifi/1.4/default/wifi_legacy_hal.cpp
+++ b/wifi/1.4/default/wifi_legacy_hal.cpp
@@ -831,6 +831,16 @@
global_handle_, mode, completion_window);
}
+wifi_error WifiLegacyHal::setDscpToAccessCategoryMapping(
+ uint32_t start, uint32_t end, uint32_t access_category) {
+ return global_func_table_.wifi_map_dscp_access_category(
+ global_handle_, start, end, access_category);
+}
+
+wifi_error WifiLegacyHal::resetDscpToAccessCategoryMapping() {
+ return global_func_table_.wifi_reset_dscp_mapping(global_handle_);
+}
+
std::pair<wifi_error, uint32_t> WifiLegacyHal::getLoggerSupportedFeatureSet(
const std::string& iface_name) {
uint32_t supported_feature_flags;
diff --git a/wifi/1.4/default/wifi_legacy_hal.h b/wifi/1.4/default/wifi_legacy_hal.h
index 72cf197..c21563e 100644
--- a/wifi/1.4/default/wifi_legacy_hal.h
+++ b/wifi/1.4/default/wifi_legacy_hal.h
@@ -261,6 +261,9 @@
wifi_latency_mode mode);
wifi_error setThermalMitigationMode(wifi_thermal_mode mode,
uint32_t completion_window);
+ wifi_error setDscpToAccessCategoryMapping(uint32_t start, uint32_t end,
+ uint32_t access_category);
+ wifi_error resetDscpToAccessCategoryMapping();
// Logger/debug functions.
std::pair<wifi_error, uint32_t> getLoggerSupportedFeatureSet(
const std::string& iface_name);
diff --git a/wifi/1.4/default/wifi_legacy_hal_stubs.cpp b/wifi/1.4/default/wifi_legacy_hal_stubs.cpp
index 6945b4c..153a685 100644
--- a/wifi/1.4/default/wifi_legacy_hal_stubs.cpp
+++ b/wifi/1.4/default/wifi_legacy_hal_stubs.cpp
@@ -141,6 +141,8 @@
populateStubFor(&hal_fn->wifi_set_thermal_mitigation_mode);
populateStubFor(&hal_fn->wifi_virtual_interface_create);
populateStubFor(&hal_fn->wifi_virtual_interface_delete);
+ populateStubFor(&hal_fn->wifi_map_dscp_access_category);
+ populateStubFor(&hal_fn->wifi_reset_dscp_mapping);
return true;
}
} // namespace legacy_hal