Merge "Improve the comments of Thermal HAL 2.0 API"
diff --git a/camera/device/3.4/default/CameraDeviceSession.cpp b/camera/device/3.4/default/CameraDeviceSession.cpp
index c937834..e00b3f8 100644
--- a/camera/device/3.4/default/CameraDeviceSession.cpp
+++ b/camera/device/3.4/default/CameraDeviceSession.cpp
@@ -128,7 +128,9 @@
     }
 
     camera3_stream_configuration_t stream_list{};
-    stream_list.stream_configuration_counter = streamConfigCounter;
+    // Block reading mStreamConfigCounter until configureStream returns
+    Mutex::Autolock _sccl(mStreamConfigCounterLock);
+    mStreamConfigCounter = streamConfigCounter;
     hidl_vec<camera3_stream_t*> streams;
     stream_list.session_parameters = paramBuffer;
     if (!preProcessConfigurationLocked_3_4(requestedConfiguration, &stream_list, &streams)) {
diff --git a/camera/device/3.4/default/include/device_v3_4_impl/CameraDeviceSession.h b/camera/device/3.4/default/include/device_v3_4_impl/CameraDeviceSession.h
index 00500b1..1db7b41 100644
--- a/camera/device/3.4/default/include/device_v3_4_impl/CameraDeviceSession.h
+++ b/camera/device/3.4/default/include/device_v3_4_impl/CameraDeviceSession.h
@@ -123,6 +123,10 @@
     // Physical camera ids for the logical multi-camera. Empty if this
     // is not a logical multi-camera.
     std::unordered_set<std::string> mPhysicalCameraIds;
+
+    Mutex    mStreamConfigCounterLock;
+    uint32_t mStreamConfigCounter = 1;
+
 private:
 
     struct TrampolineSessionInterface_3_4 : public ICameraDeviceSession {
diff --git a/camera/device/3.5/default/CameraDeviceSession.cpp b/camera/device/3.5/default/CameraDeviceSession.cpp
index 873ddd0..bea1be6 100644
--- a/camera/device/3.5/default/CameraDeviceSession.cpp
+++ b/camera/device/3.5/default/CameraDeviceSession.cpp
@@ -72,6 +72,22 @@
 
 Return<void> CameraDeviceSession::signalStreamFlush(
         const hidl_vec<int32_t>& streamIds, uint32_t streamConfigCounter) {
+    if (mDevice->ops->signal_stream_flush == nullptr) {
+        return Void();
+    }
+
+    uint32_t currentCounter = 0;
+    {
+        Mutex::Autolock _l(mStreamConfigCounterLock);
+        currentCounter = mStreamConfigCounter;
+    }
+
+    if (streamConfigCounter < currentCounter) {
+        ALOGV("%s: streamConfigCounter %d is stale (current %d), skipping signal_stream_flush call",
+                __FUNCTION__, streamConfigCounter, mStreamConfigCounter);
+        return Void();
+    }
+
     std::vector<camera3_stream_t*> streams(streamIds.size());
     {
         Mutex::Autolock _l(mInflightLock);
@@ -84,10 +100,8 @@
             streams[i] = &mStreamMap[id];
         }
     }
-    if (mDevice->ops->signal_stream_flush != nullptr) {
-        mDevice->ops->signal_stream_flush(mDevice,
-                streamConfigCounter, streams.size(), streams.data());
-    }
+
+    mDevice->ops->signal_stream_flush(mDevice, streams.size(), streams.data());
     return Void();
 }
 
diff --git a/input/classifier/1.0/vts/OWNERS b/input/classifier/1.0/vts/OWNERS
new file mode 100644
index 0000000..447f3d9
--- /dev/null
+++ b/input/classifier/1.0/vts/OWNERS
@@ -0,0 +1,3 @@
+michaelwr@google.com
+pquinn@google.com
+svv@google.com
\ No newline at end of file
diff --git a/input/classifier/1.0/vts/functional/Android.bp b/input/classifier/1.0/vts/functional/Android.bp
new file mode 100644
index 0000000..ef49d70
--- /dev/null
+++ b/input/classifier/1.0/vts/functional/Android.bp
@@ -0,0 +1,27 @@
+//
+// Copyright (C) 2019 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: "VtsHalInputClassifierV1_0TargetTest",
+    defaults: ["VtsHalTargetTestDefaults"],
+    srcs: ["VtsHalInputClassifierV1_0TargetTest.cpp"],
+    static_libs: [
+        "android.hardware.input.classifier@1.0",
+        "android.hardware.input.common@1.0",
+    ],
+    test_suites: ["general-tests"],
+}
+
diff --git a/input/classifier/1.0/vts/functional/VtsHalInputClassifierV1_0TargetTest.cpp b/input/classifier/1.0/vts/functional/VtsHalInputClassifierV1_0TargetTest.cpp
new file mode 100644
index 0000000..f033c2a
--- /dev/null
+++ b/input/classifier/1.0/vts/functional/VtsHalInputClassifierV1_0TargetTest.cpp
@@ -0,0 +1,193 @@
+/*
+ * Copyright (C) 2019 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 "input_classifier_hal_test"
+
+#include <VtsHalHidlTargetTestBase.h>
+#include <VtsHalHidlTargetTestEnvBase.h>
+#include <android-base/logging.h>
+#include <android/hardware/input/classifier/1.0/IInputClassifier.h>
+#include <android/hardware/input/common/1.0/types.h>
+#include <input/InputDevice.h>
+#include <unistd.h>
+
+using ::android::ReservedInputDeviceId;
+using ::android::sp;
+using ::android::hardware::Return;
+using ::android::hardware::input::classifier::V1_0::IInputClassifier;
+using ::android::hardware::input::common::V1_0::Action;
+using ::android::hardware::input::common::V1_0::Axis;
+using ::android::hardware::input::common::V1_0::Button;
+using ::android::hardware::input::common::V1_0::EdgeFlag;
+using ::android::hardware::input::common::V1_0::MotionEvent;
+using ::android::hardware::input::common::V1_0::PointerCoords;
+using ::android::hardware::input::common::V1_0::PointerProperties;
+using ::android::hardware::input::common::V1_0::Source;
+using ::android::hardware::input::common::V1_0::ToolType;
+using ::android::hardware::input::common::V1_0::VideoFrame;
+
+static MotionEvent getSimpleMotionEvent() {
+    MotionEvent event;
+    event.action = Action::DOWN;
+    event.actionButton = Button::NONE;
+    event.actionIndex = 0;
+    event.buttonState = 0;
+    event.deviceId = 0;
+    event.deviceTimestamp = 0;
+    event.displayId = 1;
+    event.downTime = 2;
+    event.edgeFlags = 0;
+    event.eventTime = 3;
+    event.flags = 0;
+    event.frames = {};
+    event.metaState = 0;
+    event.policyFlags = 0;
+    event.source = Source::TOUCHSCREEN;
+    event.xPrecision = 0;
+    event.yPrecision = 0;
+
+    PointerCoords coords;
+    coords.bits = Axis::X | Axis::Y;
+    coords.values = {1 /*X*/, 2 /*Y*/};
+    event.pointerCoords = {coords};
+
+    PointerProperties properties;
+    properties.id = 0;
+    properties.toolType = ToolType::FINGER;
+    event.pointerProperties = {properties};
+
+    return event;
+}
+
+// Test environment for Input Classifier HIDL HAL.
+class InputClassifierHidlEnvironment : public ::testing::VtsHalHidlTargetTestEnvBase {
+  public:
+    // get the test environment singleton
+    static InputClassifierHidlEnvironment* Instance() {
+        static InputClassifierHidlEnvironment* instance = new InputClassifierHidlEnvironment;
+        return instance;
+    }
+
+    virtual void registerTestServices() override { registerTestService<IInputClassifier>(); }
+
+  private:
+    InputClassifierHidlEnvironment() {}
+};
+
+// The main test class for INPUT CLASSIFIER HIDL HAL 1.0.
+class InputClassifierHidlTest_1_0 : public ::testing::VtsHalHidlTargetTestBase {
+  public:
+    virtual void SetUp() override {
+        classifier = ::testing::VtsHalHidlTargetTestBase::getService<IInputClassifier>(
+                InputClassifierHidlEnvironment::Instance()->getServiceName<IInputClassifier>());
+        ASSERT_NE(classifier, nullptr);
+    }
+
+    virtual void TearDown() override {}
+
+    sp<IInputClassifier> classifier;
+};
+
+/**
+ * Call resetDevice(..) for a few common device id values, and make sure that the HAL
+ * can handle the resets gracefully.
+ */
+TEST_F(InputClassifierHidlTest_1_0, ResetDevice) {
+    EXPECT_TRUE(classifier->resetDevice(ReservedInputDeviceId::VIRTUAL_KEYBOARD_ID).isOk());
+    EXPECT_TRUE(classifier->resetDevice(ReservedInputDeviceId::BUILT_IN_KEYBOARD_ID).isOk());
+    EXPECT_TRUE(classifier->resetDevice(1).isOk());
+    EXPECT_TRUE(classifier->resetDevice(2).isOk());
+}
+
+/**
+ * Call reset() on the HAL to ensure no fatal failure there.
+ */
+TEST_F(InputClassifierHidlTest_1_0, ResetHal) {
+    EXPECT_TRUE(classifier->reset().isOk());
+}
+
+/**
+ * Classify an event without any video frames.
+ */
+TEST_F(InputClassifierHidlTest_1_0, Classify_NoVideoFrame) {
+    // Create a MotionEvent that does not have any video data
+    MotionEvent event = getSimpleMotionEvent();
+
+    EXPECT_TRUE(classifier->classify(event).isOk());
+    // We are not checking the actual classification here,
+    // because the HAL operation is highly device-specific.
+
+    // Return HAL to a consistent state by doing a reset
+    classifier->reset();
+}
+
+/**
+ * Classify an event with one video frame. Should be the most common scenario.
+ */
+TEST_F(InputClassifierHidlTest_1_0, Classify_OneVideoFrame) {
+    MotionEvent event = getSimpleMotionEvent();
+    VideoFrame frame;
+    frame.data = {1, 2, 3, 4};
+    frame.height = 2;
+    frame.width = 2;
+    frame.timestamp = event.eventTime;
+    event.frames = {frame};
+
+    EXPECT_TRUE(classifier->classify(event).isOk());
+    // We are not checking the actual classification here,
+    // because the HAL operation is highly device-specific.
+
+    // Return HAL to a consistent state by doing a reset
+    classifier->reset();
+}
+
+/**
+ * Classify an event with 2 video frames. This could happen if there's slowness in the system,
+ * or if simply the video rate is somehow higher that the input event rate.
+ * The HAL should be able to handle events with more than 1 video frame.
+ *
+ * The frames should be in chronological order, but it is not guaranteed that they will have
+ * monotonically increasing timestamps. Still, we provide consistent timestamps here since that
+ * is the most realistic mode of operation.
+ */
+TEST_F(InputClassifierHidlTest_1_0, Classify_TwoVideoFrames) {
+    MotionEvent event = getSimpleMotionEvent();
+    VideoFrame frame1;
+    frame1.data = {1, 2, 3, 4};
+    frame1.height = 2;
+    frame1.width = 2;
+    frame1.timestamp = event.eventTime;
+    VideoFrame frame2 = frame1;
+    frame2.data = {5, 5, 5, -1};
+    frame2.timestamp += 1;
+    event.frames = {frame1, frame2};
+
+    EXPECT_TRUE(classifier->classify(event).isOk());
+    // We are not checking the actual classification here,
+    // because the HAL operation is highly device-specific.
+
+    // Return HAL to a consistent state by doing a reset
+    classifier->reset();
+}
+
+int main(int argc, char** argv) {
+    ::testing::AddGlobalTestEnvironment(InputClassifierHidlEnvironment::Instance());
+    ::testing::InitGoogleTest(&argc, argv);
+    InputClassifierHidlEnvironment::Instance()->init(&argc, argv);
+    int status = RUN_ALL_TESTS();
+    LOG(INFO) << "Test result = " << status;
+    return status;
+}
diff --git a/neuralnetworks/1.0/vts/functional/GeneratedTestHarness.cpp b/neuralnetworks/1.0/vts/functional/GeneratedTestHarness.cpp
index 0724c09..7eea7fc 100644
--- a/neuralnetworks/1.0/vts/functional/GeneratedTestHarness.cpp
+++ b/neuralnetworks/1.0/vts/functional/GeneratedTestHarness.cpp
@@ -72,7 +72,8 @@
     copy_back_(&dst->bool8Operands, ra, src);
     copy_back_(&dst->quant8ChannelOperands, ra, src);
     copy_back_(&dst->quant16AsymmOperands, ra, src);
-    static_assert(8 == MixedTyped::kNumTypes,
+    copy_back_(&dst->quant8SymmOperands, ra, src);
+    static_assert(9 == MixedTyped::kNumTypes,
                   "Number of types in MixedTyped changed, but copy_back function wasn't updated");
 }
 
diff --git a/radio/1.4/vts/functional/radio_hidl_hal_api.cpp b/radio/1.4/vts/functional/radio_hidl_hal_api.cpp
index 9237799..f9404d2 100644
--- a/radio/1.4/vts/functional/radio_hidl_hal_api.cpp
+++ b/radio/1.4/vts/functional/radio_hidl_hal_api.cpp
@@ -93,4 +93,59 @@
     ALOGI("emergencyDial_withEmergencyRouting, rspInfo.error = %s\n",
           toString(radioRsp_v1_4->rspInfo.error).c_str());
     EXPECT_EQ(RadioError::NONE, radioRsp_v1_4->rspInfo.error);
-}
\ No newline at end of file
+}
+
+/*
+ * Test IRadio.setupDataCall_1_4() for the response returned.
+ */
+TEST_F(RadioHidlTest_v1_4, setupDataCall_1_4) {
+    serial = GetRandomSerialNumber();
+
+    ::android::hardware::radio::V1_4::AccessNetwork accessNetwork =
+            ::android::hardware::radio::V1_4::AccessNetwork::EUTRAN;
+
+    android::hardware::radio::V1_4::DataProfileInfo dataProfileInfo;
+    memset(&dataProfileInfo, 0, sizeof(dataProfileInfo));
+    dataProfileInfo.profileId = DataProfileId::DEFAULT;
+    dataProfileInfo.apn = hidl_string("internet");
+    dataProfileInfo.protocol = PdpProtocolType::IPV4V6;
+    dataProfileInfo.roamingProtocol = PdpProtocolType::IPV4V6;
+    dataProfileInfo.authType = ApnAuthType::NO_PAP_NO_CHAP;
+    dataProfileInfo.user = hidl_string("username");
+    dataProfileInfo.password = hidl_string("password");
+    dataProfileInfo.type = DataProfileInfoType::THREE_GPP;
+    dataProfileInfo.maxConnsTime = 300;
+    dataProfileInfo.maxConns = 20;
+    dataProfileInfo.waitTime = 0;
+    dataProfileInfo.enabled = true;
+    dataProfileInfo.supportedApnTypesBitmap = 320;
+    dataProfileInfo.bearerBitmap = 161543;
+    dataProfileInfo.mtu = 0;
+    dataProfileInfo.preferred = true;
+    dataProfileInfo.persistent = false;
+
+    bool roamingAllowed = false;
+
+    ::android::hardware::radio::V1_2::DataRequestReason reason =
+            ::android::hardware::radio::V1_2::DataRequestReason::NORMAL;
+    std::vector<hidl_string> addresses = {""};
+    std::vector<hidl_string> dnses = {""};
+
+    Return<void> res = radio_v1_4->setupDataCall_1_4(serial, accessNetwork, dataProfileInfo,
+                                                     roamingAllowed, reason, addresses, dnses);
+    ASSERT_OK(res);
+
+    EXPECT_EQ(std::cv_status::no_timeout, wait());
+    EXPECT_EQ(RadioResponseType::SOLICITED, radioRsp_v1_4->rspInfo.type);
+    EXPECT_EQ(serial, radioRsp_v1_4->rspInfo.serial);
+
+    if (cardStatus.base.base.cardState == CardState::ABSENT) {
+        ASSERT_TRUE(CheckAnyOfErrors(radioRsp_v1_4->rspInfo.error,
+                                     {RadioError::SIM_ABSENT, RadioError::RADIO_NOT_AVAILABLE,
+                                      RadioError::OP_NOT_ALLOWED_BEFORE_REG_TO_NW}));
+    } else if (cardStatus.base.base.cardState == CardState::PRESENT) {
+        ASSERT_TRUE(CheckAnyOfErrors(radioRsp_v1_4->rspInfo.error,
+                                     {RadioError::NONE, RadioError::RADIO_NOT_AVAILABLE,
+                                      RadioError::OP_NOT_ALLOWED_BEFORE_REG_TO_NW}));
+    }
+}