Merge "cas@1.1: must be used over cas@1.0 for Q devices"
diff --git a/audio/common/5.0/types.hal b/audio/common/5.0/types.hal
index ffe4506..8f8a888 100644
--- a/audio/common/5.0/types.hal
+++ b/audio/common/5.0/types.hal
@@ -643,8 +643,10 @@
             int32_t device;
         } alsa;             // used for USB_*
     } address;
-    string busAddress;      // used for BUS
-    string rSubmixAddress;  // used for REMOTE_SUBMIX
+    /** Arbitrary BUS device unique address. Should not be interpreted by the framework. */
+    string busAddress;
+    /** Arbitrary REMOTE_SUBMIX device unique address. Should not be interpreted by the HAL. */
+    string rSubmixAddress;
 };
 
 /**
diff --git a/audio/core/all-versions/vts/functional/AudioPrimaryHidlHalTest.h b/audio/core/all-versions/vts/functional/AudioPrimaryHidlHalTest.h
index a22cc1c..7f8b6a0 100644
--- a/audio/core/all-versions/vts/functional/AudioPrimaryHidlHalTest.h
+++ b/audio/core/all-versions/vts/functional/AudioPrimaryHidlHalTest.h
@@ -142,14 +142,13 @@
     android::DeviceVector availableOutputDevices;
     android::DeviceVector availableInputDevices;
     sp<android::DeviceDescriptor> defaultOutputDevice;
-    android::VolumeCurvesCollection volumes;
 };
 
 class PolicyConfig : private PolicyConfigData, public AudioPolicyConfig {
    public:
     PolicyConfig()
         : AudioPolicyConfig(hwModules, availableOutputDevices, availableInputDevices,
-                            defaultOutputDevice, &volumes) {
+                            defaultOutputDevice) {
         for (const char* location : kConfigLocations) {
             std::string path = std::string(location) + '/' + kConfigFileName;
             if (access(path.c_str(), F_OK) == 0) {
diff --git a/current.txt b/current.txt
index a128669..4aa8c1d 100644
--- a/current.txt
+++ b/current.txt
@@ -418,7 +418,7 @@
 9471b12b1c255bb530695720bc4174bd74987b75b1f820854af8944bc8c215c9 android.hardware.audio@5.0::IStreamOut
 1b0500367ed2b32a841667ac3200edf3d3a164e8004aca445ff1b085ac831e93 android.hardware.audio@5.0::IStreamOutCallback
 83e365479cc77d8717c155e1787ee668cd2ae4c557b467cf75b8e7cd53697ad8 android.hardware.audio@5.0::types
-edda213e520f387a3e367834b0772978b308a0f59b54479990aa9411aee9bcc4 android.hardware.audio.common@5.0::types
+894af04bebfe7da5b6791eefeb6eb3627da63d5efea735f16876d11d8ca4f61d android.hardware.audio.common@5.0::types
 f269297866765b95ddd1825676cc8a772f0c7c9863286df596fc302781a42ff5 android.hardware.audio.effect@5.0::IAcousticEchoCancelerEffect
 fa187b602d8939644ef708ed7627f2e3deac97899a4bda1de07f2ff126abe243 android.hardware.audio.effect@5.0::IAutomaticGainControlEffect
 e1bf864ccb8458c0da1dcc74a2e748b1dca8ac360df590591cf82d98292d7981 android.hardware.audio.effect@5.0::IBassBoostEffect
@@ -487,7 +487,7 @@
 dd1ec219f5d2e2b33c6c0bcb92e63bbedb36f7c716413462848f6b6ae74fc864 android.hardware.health.storage@1.0::IStorage
 2b4a14661e6a38617b7dd0c6ebb66a56a90e564674ac7697a14cb8a0cab92b2f android.hardware.health.storage@1.0::types
 30006fde4cb1f255f2530208728bff692100411b20af5b66fa31a9196d51f00b android.hardware.input.classifier@1.0::IInputClassifier
-97d8757bb05eb23d6a218bda374e095dfbb064c47714e2f859963c11f433e822 android.hardware.input.common@1.0::types
+0300c7667030da36c3de585f176ce18ff4b0d2615446d4930f331097378c06ef android.hardware.input.common@1.0::types
 24ae089981d58bc4cc74d75a6055bf357338ae6744ce1b467c5b4a9c470aba6d android.hardware.media.bufferpool@2.0::IAccessor
 897f45ee7db24ef227dea83ca3e4de72d53ff6bb7adc7983c90a650a1a6ff576 android.hardware.media.bufferpool@2.0::IClientManager
 aee53b2865b4f7939fb3df6fae758d9750c14f93dd454b479fc74aa7978fda4f android.hardware.media.bufferpool@2.0::IConnection
@@ -512,12 +512,12 @@
 cf7a4ba516a638f9b82a249c91fb603042c2d9ca43fd5aad9cf6c0401ed2a5d7 android.hardware.nfc@1.2::INfc
 abf98c2ae08bf765db54edc8068e36d52eb558cff6706b6fd7c18c65a1f3fc18 android.hardware.nfc@1.2::types
 4cb252dc6372a874aef666b92a6e9529915aa187521a700f0789065c3c702ead android.hardware.power.stats@1.0::IPowerStats
-69c394e7fe3236beb6231a709865e8a882aac7a612c8dddf64f5a66028fa2c68 android.hardware.power.stats@1.0::types
+2043037d5baaff604805757d06979aa861013a1e87430db745265339a8681f79 android.hardware.power.stats@1.0::types
 11620ce020b6ef8f5b63eb2a39390de4a2fbbccc0a5e558b5b1a0e22e33f63cf android.hardware.radio@1.3::IRadio
 e9d0f11a52715f5a29d89e2d8e2e21db1e16a43174af6b9d51a62d705cda1455 android.hardware.radio@1.3::IRadioIndication
 d233f0da44f55fdef0a95db5229231412787bb67695cd1ea197ce89a3c2908b9 android.hardware.radio@1.3::IRadioResponse
 750a363c8cec70baa1aac19e275c15233c5898e93c6bb5155fa2ca7f365490dc android.hardware.radio@1.3::types
-21e6ce53f1759f6a213ca05bac3c0325ed911f74764d1c1f6fa5ed8068ade65b android.hardware.radio@1.4::IRadio
+4ac73ec1e4cfa535209e5e22547f08beb20ef812b4a29d0824780f52cbe2324d android.hardware.radio@1.4::IRadio
 33d9e6895cca98aa56296bb01720d18b8acd0e4de4960beb712e63ad147438a5 android.hardware.radio@1.4::IRadioIndication
 0cc0dd87c634aad36d7df22b2832839ef7ded71909dbcde11cfdd69dc0dc52b8 android.hardware.radio@1.4::IRadioResponse
 29d34232cc3974626b08759e039fe788bded7695cdeb098458e3e11e4c7d3603 android.hardware.radio@1.4::types
@@ -534,7 +534,7 @@
 ae5faa38538a9f50eb71eb7f9b998271124d2c64b761cb11c4d820c7732b4ddc android.hardware.sensors@2.0::ISensorsCallback
 3a98242a57d0820dacaca0f7db52bec433eae1f21c498763c6f1ece611c3967b android.hardware.sensors@2.0::types
 ce4b98211959449361146d4b1e5554dc841ceb4d4577154d7b2fb6d1eb504f76 android.hardware.soundtrigger@2.2::ISoundTriggerHw
-5cc81d517c5f3fef12e719b0f5683c7c99e3e8895fcb80e6f6653b454f463320 android.hardware.thermal@2.0::IThermal
+bd88b48639cae30982021024e22371076c76faa8466e38ca598529452b618eae android.hardware.thermal@2.0::IThermal
 cc4d2ef36da776c475ad054f0f3416d8a8865def9d9e2129f10074b28e36d203 android.hardware.thermal@2.0::IThermalChangedCallback
 b47f90302595874dfddb19bd05a054727bf18b3a930bc810ea14957b859ae8bf android.hardware.thermal@2.0::types
 61bc302e7c974c59b25898c585c6e9685e8a81021b1bed3eedf5224198f2785a android.hardware.usb@1.2::IUsb
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/input/common/1.0/types.hal b/input/common/1.0/types.hal
index 1a07f3b..9ad368b 100644
--- a/input/common/1.0/types.hal
+++ b/input/common/1.0/types.hal
@@ -685,20 +685,20 @@
  * Touch heatmap.
  *
  * The array is a 2-D row-major matrix with dimensions (height, width).
- * The heatmap data does not rotate when device orientation changes.
+ * The heatmap data is rotated when device orientation changes.
  *
  * Example:
  *
  * If the data in the array is:
  * data[i] = i for i in 0 .. 59,
- * then it can be represented as follows:
+ * then it can be represented as a 10 x 6 matrix:
  *
- *  <--    width   -- >
+ *  <--   width   -->
  *   0  1  2  3  4  5   ^
  *   6  7  8  9 10 11   |
- *  12 12 14 15 16 17   |
- *  18    ...      23   | height
- *  24    ...      29   |
+ *  12 13 14 15 16 17   |
+ *  18    ...      23   |
+ *  24    ...      29   | height
  *  30    ...      35   |
  *  36    ...      41   |
  *  42    ...      47   |
@@ -708,16 +708,33 @@
  * Looking at the device in standard portrait orientation,
  * the element "0" is the top left of the screen,
  * "5" is at the top right, and "59" is the bottom right.
- * Here width=6, and height=10.
+ * Here height=10 and width=6.
+ *
+ * If the screen orientation changes to landscape (a 90 degree orientation
+ * change), the frame's dimensions will become 6 x 10
+ * and the data will look as follows:
+ * 54 48 42 36 30 24 18 12  6  0     ^
+ * ...                  13  7  1     |
+ * ...                  14  8  2     | height
+ * ...                  15  9  3     |
+ * ...                  16 10  4     |
+ * 59 53 47 41 35 29 23 17 11  5     v
+ * <--        width          -->
+ *
+ * Here the element "0" is at the physical top left of the unrotated screen.
+ *
+ * Since the coordinates of a MotionEvent are also adjusted based on the
+ * orientation, the rotation of the video frame data ensures that
+ * the axes for MotionEvent and VideoFrame data are consistent.
  */
 struct VideoFrame {
     /**
      * Video frame data.
-     * Size of the data is width * height.
+     * Size of the data is height * width.
      */
     vec<int16_t> data;
-    uint32_t width;
     uint32_t height;
+    uint32_t width;
     /**
      * Time at which the frame was collected, in nanoseconds.
      * Measured with the same clock that is used to populate MotionEvent times.
diff --git a/power/stats/1.0/types.hal b/power/stats/1.0/types.hal
index 644224b..6051e3f 100644
--- a/power/stats/1.0/types.hal
+++ b/power/stats/1.0/types.hal
@@ -26,9 +26,9 @@
 struct RailInfo {
     /** Index corresponding to the rail */
     uint32_t index;
-    /** Name of the rail */
+    /** Name of the rail (opaque to the framework) */
     string railName;
-    /** Name of the subsystem to which this rail belongs */
+    /** Name of the subsystem to which this rail belongs (opaque to the framework) */
     string subsysName;
     /** Hardware sampling rate */
     uint32_t samplingRate;
@@ -71,7 +71,7 @@
 struct PowerEntityInfo {
     /** Unique ID corresponding to the PowerEntity */
     uint32_t powerEntityId;
-    /** Name of the PowerEntity */
+    /** Name of the PowerEntity (opaque to the framework) */
     string powerEntityName;
     /** Type of the PowerEntity */
     PowerEntityType type;
@@ -82,7 +82,7 @@
      * ID corresponding to the state. Unique for a given PowerEntityStateSpace
      */
     uint32_t powerEntityStateId;
-    /** Name of the state */
+    /** Name of the state (opaque to the framework) */
     string powerEntityStateName;
 };
 
diff --git a/radio/1.4/IRadio.hal b/radio/1.4/IRadio.hal
index f7ae39f..046f074 100644
--- a/radio/1.4/IRadio.hal
+++ b/radio/1.4/IRadio.hal
@@ -115,11 +115,13 @@
      * PUK/PIN state of the subscription and the service state of the radio.
      *
      * Some countries or carriers require some emergency numbers that must be handled with normal
-     * call routing or emergency routing. If the 'routing' field is specified as
-     * @1.4::EmergencyNumberRouting#NORMAL, the implementation must use normal call routing to
-     * handle the call; if it is specified as @1.4::EmergencyNumberRouting#EMERGENCY, the
-     * implementation must use emergency routing to handle the call; if it is
-     * @1.4::EmergencyNumberRouting#UNKNOWN, Android does not know how to handle the call.
+     * call routing if possible or emergency routing. 1) if the 'routing' field is specified as
+     * @1.4::EmergencyNumberRouting#NORMAL, the implementation must try the full radio service to
+     * use normal call routing to handle the call; if service cannot support normal routing, the
+     * implementation must use emergency routing to handle the call. 2) if 'routing' is specified
+     * as @1.4::EmergencyNumberRouting#EMERGENCY, the implementation must use emergency routing to
+     * handle the call. 3) if 'routing' is specified as @1.4::EmergencyNumberRouting#UNKNOWN,
+     * Android does not know how to handle the call.
      *
      * If the dialed emergency number does not have a specified emergency service category, the
      * 'categories' field is set to @1.4::EmergencyServiceCategory#UNSPECIFIED; if the dialed
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..52eb277 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,403 @@
     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.startNetworkScan() for the response returned.
+ */
+TEST_F(RadioHidlTest_v1_4, startNetworkScan) {
+    serial = GetRandomSerialNumber();
+
+    RadioAccessSpecifier specifier = {.radioAccessNetwork = RadioAccessNetworks::GERAN,
+                                      .geranBands = {GeranBands::BAND_450, GeranBands::BAND_480},
+                                      .channels = {1, 2}};
+
+    ::android::hardware::radio::V1_2::NetworkScanRequest request = {
+            .type = ScanType::ONE_SHOT, .interval = 60, .specifiers = {specifier}};
+
+    Return<void> res = radio_v1_4->startNetworkScan_1_4(serial, request);
+    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);
+
+    ALOGI("startNetworkScan, rspInfo.error = %s\n", toString(radioRsp_v1_4->rspInfo.error).c_str());
+
+    if (cardStatus.base.base.cardState == CardState::ABSENT) {
+        ASSERT_TRUE(CheckAnyOfErrors(radioRsp_v1_4->rspInfo.error, {RadioError::SIM_ABSENT}));
+    } else if (cardStatus.base.base.cardState == CardState::PRESENT) {
+        // OPERATION_NOT_ALLOWED should not be allowed; however, some vendors do not support the
+        // required manual GSM search functionality. This is tracked in b/112206766.
+        ASSERT_TRUE(CheckAnyOfErrors(radioRsp_v1_4->rspInfo.error,
+                                     {RadioError::NONE, RadioError::OPERATION_NOT_ALLOWED}));
+    }
+}
+
+/*
+ * Test IRadio.startNetworkScan() with invalid specifier.
+ */
+TEST_F(RadioHidlTest_v1_4, startNetworkScan_InvalidArgument) {
+    serial = GetRandomSerialNumber();
+
+    ::android::hardware::radio::V1_2::NetworkScanRequest request = {.type = ScanType::ONE_SHOT,
+                                                                    .interval = 60};
+
+    Return<void> res = radio_v1_4->startNetworkScan_1_4(serial, request);
+
+    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);
+
+    ALOGI("startNetworkScan_InvalidArgument, rspInfo.error = %s\n",
+          toString(radioRsp_v1_4->rspInfo.error).c_str());
+    if (cardStatus.base.base.cardState == CardState::ABSENT) {
+        ASSERT_TRUE(CheckAnyOfErrors(radioRsp_v1_4->rspInfo.error,
+                                     {RadioError::SIM_ABSENT, RadioError::INVALID_ARGUMENTS}));
+    } else if (cardStatus.base.base.cardState == CardState::PRESENT) {
+        ASSERT_TRUE(
+                CheckAnyOfErrors(radioRsp_v1_4->rspInfo.error, {RadioError::INVALID_ARGUMENTS}));
+    }
+}
+
+/*
+ * Test IRadio.startNetworkScan() with invalid interval (lower boundary).
+ */
+TEST_F(RadioHidlTest_v1_4, startNetworkScan_InvalidInterval1) {
+    serial = GetRandomSerialNumber();
+
+    RadioAccessSpecifier specifier = {.radioAccessNetwork = RadioAccessNetworks::GERAN,
+                                      .geranBands = {GeranBands::BAND_450, GeranBands::BAND_480},
+                                      .channels = {1, 2}};
+
+    ::android::hardware::radio::V1_2::NetworkScanRequest request = {
+            .type = ScanType::ONE_SHOT,
+            .interval = 4,
+            .specifiers = {specifier},
+            .maxSearchTime = 60,
+            .incrementalResults = false,
+            .incrementalResultsPeriodicity = 1};
+
+    Return<void> res = radio_v1_4->startNetworkScan_1_4(serial, request);
+
+    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);
+
+    ALOGI("startNetworkScan_InvalidInterval1, rspInfo.error = %s\n",
+          toString(radioRsp_v1_4->rspInfo.error).c_str());
+    if (cardStatus.base.base.cardState == CardState::ABSENT) {
+        ASSERT_TRUE(CheckAnyOfErrors(radioRsp_v1_4->rspInfo.error,
+                                     {RadioError::SIM_ABSENT, RadioError::INVALID_ARGUMENTS}));
+    } else if (cardStatus.base.base.cardState == CardState::PRESENT) {
+        ASSERT_TRUE(
+                CheckAnyOfErrors(radioRsp_v1_4->rspInfo.error, {RadioError::INVALID_ARGUMENTS}));
+    }
+}
+
+/*
+ * Test IRadio.startNetworkScan() with invalid interval (upper boundary).
+ */
+TEST_F(RadioHidlTest_v1_4, startNetworkScan_InvalidInterval2) {
+    serial = GetRandomSerialNumber();
+
+    RadioAccessSpecifier specifier = {.radioAccessNetwork = RadioAccessNetworks::GERAN,
+                                      .geranBands = {GeranBands::BAND_450, GeranBands::BAND_480},
+                                      .channels = {1, 2}};
+
+    ::android::hardware::radio::V1_2::NetworkScanRequest request = {
+            .type = ScanType::ONE_SHOT,
+            .interval = 301,
+            .specifiers = {specifier},
+            .maxSearchTime = 60,
+            .incrementalResults = false,
+            .incrementalResultsPeriodicity = 1};
+
+    Return<void> res = radio_v1_4->startNetworkScan_1_4(serial, request);
+    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);
+
+    ALOGI("startNetworkScan_InvalidInterval2, rspInfo.error = %s\n",
+          toString(radioRsp_v1_4->rspInfo.error).c_str());
+    if (cardStatus.base.base.cardState == CardState::ABSENT) {
+        ASSERT_TRUE(CheckAnyOfErrors(radioRsp_v1_4->rspInfo.error,
+                                     {RadioError::SIM_ABSENT, RadioError::INVALID_ARGUMENTS}));
+    } else if (cardStatus.base.base.cardState == CardState::PRESENT) {
+        ASSERT_TRUE(
+                CheckAnyOfErrors(radioRsp_v1_4->rspInfo.error, {RadioError::INVALID_ARGUMENTS}));
+    }
+}
+
+/*
+ * Test IRadio.startNetworkScan() with invalid max search time (lower boundary).
+ */
+TEST_F(RadioHidlTest_v1_4, startNetworkScan_InvalidMaxSearchTime1) {
+    serial = GetRandomSerialNumber();
+
+    RadioAccessSpecifier specifier = {.radioAccessNetwork = RadioAccessNetworks::GERAN,
+                                      .geranBands = {GeranBands::BAND_450, GeranBands::BAND_480},
+                                      .channels = {1, 2}};
+
+    ::android::hardware::radio::V1_2::NetworkScanRequest request = {
+            .type = ScanType::ONE_SHOT,
+            .interval = 60,
+            .specifiers = {specifier},
+            .maxSearchTime = 59,
+            .incrementalResults = false,
+            .incrementalResultsPeriodicity = 1};
+
+    Return<void> res = radio_v1_4->startNetworkScan_1_4(serial, request);
+    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);
+
+    ALOGI("startNetworkScan_InvalidMaxSearchTime1, rspInfo.error = %s\n",
+          toString(radioRsp_v1_4->rspInfo.error).c_str());
+    if (cardStatus.base.base.cardState == CardState::ABSENT) {
+        ASSERT_TRUE(CheckAnyOfErrors(radioRsp_v1_4->rspInfo.error,
+                                     {RadioError::SIM_ABSENT, RadioError::INVALID_ARGUMENTS}));
+    } else if (cardStatus.base.base.cardState == CardState::PRESENT) {
+        ASSERT_TRUE(
+                CheckAnyOfErrors(radioRsp_v1_4->rspInfo.error, {RadioError::INVALID_ARGUMENTS}));
+    }
+}
+
+/*
+ * Test IRadio.startNetworkScan() with invalid max search time (upper boundary).
+ */
+TEST_F(RadioHidlTest_v1_4, startNetworkScan_InvalidMaxSearchTime2) {
+    serial = GetRandomSerialNumber();
+
+    RadioAccessSpecifier specifier = {.radioAccessNetwork = RadioAccessNetworks::GERAN,
+                                      .geranBands = {GeranBands::BAND_450, GeranBands::BAND_480},
+                                      .channels = {1, 2}};
+
+    ::android::hardware::radio::V1_2::NetworkScanRequest request = {
+            .type = ScanType::ONE_SHOT,
+            .interval = 60,
+            .specifiers = {specifier},
+            .maxSearchTime = 3601,
+            .incrementalResults = false,
+            .incrementalResultsPeriodicity = 1};
+
+    Return<void> res = radio_v1_4->startNetworkScan_1_4(serial, request);
+    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);
+
+    ALOGI("startNetworkScan_InvalidMaxSearchTime2, rspInfo.error = %s\n",
+          toString(radioRsp_v1_4->rspInfo.error).c_str());
+    if (cardStatus.base.base.cardState == CardState::ABSENT) {
+        ASSERT_TRUE(CheckAnyOfErrors(radioRsp_v1_4->rspInfo.error,
+                                     {RadioError::SIM_ABSENT, RadioError::INVALID_ARGUMENTS}));
+    } else if (cardStatus.base.base.cardState == CardState::PRESENT) {
+        ASSERT_TRUE(
+                CheckAnyOfErrors(radioRsp_v1_4->rspInfo.error, {RadioError::INVALID_ARGUMENTS}));
+    }
+}
+
+/*
+ * Test IRadio.startNetworkScan() with invalid periodicity (lower boundary).
+ */
+TEST_F(RadioHidlTest_v1_4, startNetworkScan_InvalidPeriodicity1) {
+    serial = GetRandomSerialNumber();
+
+    RadioAccessSpecifier specifier = {.radioAccessNetwork = RadioAccessNetworks::GERAN,
+                                      .geranBands = {GeranBands::BAND_450, GeranBands::BAND_480},
+                                      .channels = {1, 2}};
+
+    ::android::hardware::radio::V1_2::NetworkScanRequest request = {
+            .type = ScanType::ONE_SHOT,
+            .interval = 60,
+            .specifiers = {specifier},
+            .maxSearchTime = 600,
+            .incrementalResults = false,
+            .incrementalResultsPeriodicity = 0};
+
+    Return<void> res = radio_v1_4->startNetworkScan_1_4(serial, request);
+    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);
+
+    ALOGI("startNetworkScan_InvalidPeriodicity1, rspInfo.error = %s\n",
+          toString(radioRsp_v1_4->rspInfo.error).c_str());
+    if (cardStatus.base.base.cardState == CardState::ABSENT) {
+        ASSERT_TRUE(CheckAnyOfErrors(radioRsp_v1_4->rspInfo.error,
+                                     {RadioError::SIM_ABSENT, RadioError::INVALID_ARGUMENTS}));
+    } else if (cardStatus.base.base.cardState == CardState::PRESENT) {
+        ASSERT_TRUE(
+                CheckAnyOfErrors(radioRsp_v1_4->rspInfo.error, {RadioError::INVALID_ARGUMENTS}));
+    }
+}
+
+/*
+ * Test IRadio.startNetworkScan() with invalid periodicity (upper boundary).
+ */
+TEST_F(RadioHidlTest_v1_4, startNetworkScan_InvalidPeriodicity2) {
+    serial = GetRandomSerialNumber();
+
+    RadioAccessSpecifier specifier = {.radioAccessNetwork = RadioAccessNetworks::GERAN,
+                                      .geranBands = {GeranBands::BAND_450, GeranBands::BAND_480},
+                                      .channels = {1, 2}};
+
+    ::android::hardware::radio::V1_2::NetworkScanRequest request = {
+            .type = ScanType::ONE_SHOT,
+            .interval = 60,
+            .specifiers = {specifier},
+            .maxSearchTime = 600,
+            .incrementalResults = false,
+            .incrementalResultsPeriodicity = 11};
+
+    Return<void> res = radio_v1_4->startNetworkScan_1_4(serial, request);
+    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);
+
+    ALOGI("startNetworkScan_InvalidPeriodicity2, rspInfo.error = %s\n",
+          toString(radioRsp_v1_4->rspInfo.error).c_str());
+    if (cardStatus.base.base.cardState == CardState::ABSENT) {
+        ASSERT_TRUE(CheckAnyOfErrors(radioRsp_v1_4->rspInfo.error,
+                                     {RadioError::SIM_ABSENT, RadioError::INVALID_ARGUMENTS}));
+    } else if (cardStatus.base.base.cardState == CardState::PRESENT) {
+        ASSERT_TRUE(
+                CheckAnyOfErrors(radioRsp_v1_4->rspInfo.error, {RadioError::INVALID_ARGUMENTS}));
+    }
+}
+
+/*
+ * Test IRadio.startNetworkScan() with valid periodicity
+ */
+TEST_F(RadioHidlTest_v1_4, startNetworkScan_GoodRequest1) {
+    serial = GetRandomSerialNumber();
+
+    RadioAccessSpecifier specifier = {.radioAccessNetwork = RadioAccessNetworks::GERAN,
+                                      .geranBands = {GeranBands::BAND_450, GeranBands::BAND_480},
+                                      .channels = {1, 2}};
+
+    ::android::hardware::radio::V1_2::NetworkScanRequest request = {
+            .type = ScanType::ONE_SHOT,
+            .interval = 60,
+            .specifiers = {specifier},
+            // Some vendor may not support max search time of 360s.
+            // This issue is tracked in b/112205669.
+            .maxSearchTime = 300,
+            .incrementalResults = false,
+            .incrementalResultsPeriodicity = 10};
+
+    Return<void> res = radio_v1_4->startNetworkScan_1_4(serial, request);
+    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);
+
+    ALOGI("startNetworkScan_GoodRequest1, rspInfo.error = %s\n",
+          toString(radioRsp_v1_4->rspInfo.error).c_str());
+    if (cardStatus.base.base.cardState == CardState::ABSENT) {
+        ASSERT_TRUE(CheckAnyOfErrors(radioRsp_v1_4->rspInfo.error,
+                                     {RadioError::NONE, RadioError::SIM_ABSENT}));
+    } else if (cardStatus.base.base.cardState == CardState::PRESENT) {
+        ASSERT_TRUE(CheckAnyOfErrors(radioRsp_v1_4->rspInfo.error,
+                                     {RadioError::NONE, RadioError::INVALID_ARGUMENTS}));
+    }
+}
+
+/*
+ * Test IRadio.startNetworkScan() with valid periodicity and plmns
+ */
+TEST_F(RadioHidlTest_v1_4, startNetworkScan_GoodRequest2) {
+    serial = GetRandomSerialNumber();
+
+    RadioAccessSpecifier specifier = {.radioAccessNetwork = RadioAccessNetworks::GERAN,
+                                      .geranBands = {GeranBands::BAND_450, GeranBands::BAND_480},
+                                      .channels = {1, 2}};
+
+    ::android::hardware::radio::V1_2::NetworkScanRequest request = {
+            .type = ScanType::ONE_SHOT,
+            .interval = 60,
+            .specifiers = {specifier},
+            // Some vendor may not support max search time of 360s.
+            // This issue is tracked in b/112205669.
+            .maxSearchTime = 300,
+            .incrementalResults = false,
+            .incrementalResultsPeriodicity = 10,
+            .mccMncs = {"310410"}};
+
+    Return<void> res = radio_v1_4->startNetworkScan_1_4(serial, request);
+
+    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);
+
+    ALOGI("startNetworkScan_GoodRequest2, rspInfo.error = %s\n",
+          toString(radioRsp_v1_4->rspInfo.error).c_str());
+    if (cardStatus.base.base.cardState == CardState::ABSENT) {
+        ASSERT_TRUE(CheckAnyOfErrors(radioRsp_v1_4->rspInfo.error,
+                                     {RadioError::NONE, RadioError::SIM_ABSENT}));
+    } else if (cardStatus.base.base.cardState == CardState::PRESENT) {
+        ASSERT_TRUE(CheckAnyOfErrors(radioRsp_v1_4->rspInfo.error,
+                                     {RadioError::NONE, RadioError::INVALID_ARGUMENTS}));
+    }
+}
+/*
+ * 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}));
+    }
+}
diff --git a/thermal/2.0/IThermal.hal b/thermal/2.0/IThermal.hal
index f890694..3ea4590 100644
--- a/thermal/2.0/IThermal.hal
+++ b/thermal/2.0/IThermal.hal
@@ -56,22 +56,24 @@
      *    they go offline, if these devices exist on boot. The method
      *    always returns and never removes such temperatures. The thresholds
      *    are returned as static values and must not change across calls. The actual
-     *    throttling state is determined in driver and HAL and must not be simply
-     *    compared with these thresholds. To get accurate throttling status, use
-     *    getCurrentTemperatures or registerThermalChangedCallback and listen.
+     *    throttling state is determined in device thermal mitigation policy/agorithm
+     *    which might not be simple thresholds so these values Thermal HAL provided
+     *    may not be accurate to detemin the throttling status. To get accurate
+     *    throttling status, use getCurrentTemperatures or registerThermalChangedCallback
+     *    and listen to the callback.
      */
     getTemperatureThresholds(bool filterType, TemperatureType type)
         generates (ThermalStatus status, vec<TemperatureThreshold> temperatureThresholds);
 
    /**
     * Register an IThermalChangedCallback, used by the Thermal HAL
-    * to send thermal events when thermal mitigation status changed.
+    * to receive thermal events when thermal mitigation status changed.
     * Multiple registrations with different IThermalChangedCallback must be allowed.
     * Multiple registrations with same IThermalChangedCallback is not allowed, client
     * should unregister the given IThermalChangedCallback first.
     *
-    * @param callback the IThermalChangedCallback to use for sending
-    *    thermal events (cannot be nullptr).
+    * @param callback the IThermalChangedCallback to use for receiving
+    *    thermal events (nullptr callback will lead to failure with status code FAILURE).
     * @param filterType if filter for given sensor type.
     * @param type the type to be filtered.
     *
@@ -84,11 +86,11 @@
        generates (ThermalStatus status);
 
    /**
-    * Register an IThermalChangedCallback, used by the Thermal HAL
-    * to send thermal events when thermal mitigation status changed.
+    * Unregister an IThermalChangedCallback, used by the Thermal HAL
+    * to receive thermal events when thermal mitigation status changed.
     *
-    * @param callback the IThermalChangedCallback to use for sending
-    *    thermal events, or nullptr to set no callback.
+    * @param callback the IThermalChangedCallback used for receiving
+    *    thermal events (nullptr callback will lead to failure with status code FAILURE).
     *
     * @return status Status of the operation. If status code is FAILURE,
     *    the status.debugMessage must be populated with a human-readable error message.
diff --git a/thermal/2.0/default/Thermal.cpp b/thermal/2.0/default/Thermal.cpp
index 442af61..0ef4b63 100644
--- a/thermal/2.0/default/Thermal.cpp
+++ b/thermal/2.0/default/Thermal.cpp
@@ -155,7 +155,15 @@
                                                      bool filterType, TemperatureType type,
                                                      registerThermalChangedCallback_cb _hidl_cb) {
     ThermalStatus status;
-    status.code = ThermalStatusCode::SUCCESS;
+    if (callback == nullptr) {
+        status.code = ThermalStatusCode::FAILURE;
+        status.debugMessage = "Invalid nullptr callback";
+        LOG(ERROR) << status.debugMessage;
+        _hidl_cb(status);
+        return Void();
+    } else {
+        status.code = ThermalStatusCode::SUCCESS;
+    }
     std::lock_guard<std::mutex> _lock(thermal_callback_mutex_);
     if (std::any_of(callbacks_.begin(), callbacks_.end(), [&](const CallbackSetting& c) {
             return interfacesEqual(c.callback, callback);
@@ -175,7 +183,15 @@
 Return<void> Thermal::unregisterThermalChangedCallback(
     const sp<IThermalChangedCallback>& callback, unregisterThermalChangedCallback_cb _hidl_cb) {
     ThermalStatus status;
-    status.code = ThermalStatusCode::SUCCESS;
+    if (callback == nullptr) {
+        status.code = ThermalStatusCode::FAILURE;
+        status.debugMessage = "Invalid nullptr callback";
+        LOG(ERROR) << status.debugMessage;
+        _hidl_cb(status);
+        return Void();
+    } else {
+        status.code = ThermalStatusCode::SUCCESS;
+    }
     bool removed = false;
     std::lock_guard<std::mutex> _lock(thermal_callback_mutex_);
     callbacks_.erase(
diff --git a/thermal/2.0/vts/functional/VtsHalThermalV2_0TargetTest.cpp b/thermal/2.0/vts/functional/VtsHalThermalV2_0TargetTest.cpp
index 3893014..cc2f3df 100644
--- a/thermal/2.0/vts/functional/VtsHalThermalV2_0TargetTest.cpp
+++ b/thermal/2.0/vts/functional/VtsHalThermalV2_0TargetTest.cpp
@@ -132,8 +132,13 @@
 TEST_F(ThermalHidlTest, RegisterThermalChangedCallbackTest) {
     // Expect to fail with same callback
     auto ret = mThermal->registerThermalChangedCallback(
-        mThermalCallback, false, TemperatureType::SKIN,
-        [](ThermalStatus status) { EXPECT_NE(ThermalStatusCode::SUCCESS, status.code); });
+            mThermalCallback, false, TemperatureType::SKIN,
+            [](ThermalStatus status) { EXPECT_EQ(ThermalStatusCode::FAILURE, status.code); });
+    ASSERT_TRUE(ret.isOk());
+    // Expect to fail with null callback
+    ret = mThermal->registerThermalChangedCallback(
+            nullptr, false, TemperatureType::SKIN,
+            [](ThermalStatus status) { EXPECT_EQ(ThermalStatusCode::FAILURE, status.code); });
     ASSERT_TRUE(ret.isOk());
     sp<ThermalCallback> localThermalCallback = new (std::nothrow) ThermalCallback();
     // Expect to succeed with different callback
@@ -141,11 +146,16 @@
         localThermalCallback, false, TemperatureType::SKIN,
         [](ThermalStatus status) { EXPECT_EQ(ThermalStatusCode::SUCCESS, status.code); });
     ASSERT_TRUE(ret.isOk());
-    // Remove the local callback.
+    // Remove the local callback
     ret = mThermal->unregisterThermalChangedCallback(
         localThermalCallback,
         [](ThermalStatus status) { EXPECT_EQ(ThermalStatusCode::SUCCESS, status.code); });
     ASSERT_TRUE(ret.isOk());
+    // Expect to fail with null callback
+    ret = mThermal->unregisterThermalChangedCallback(nullptr, [](ThermalStatus status) {
+        EXPECT_EQ(ThermalStatusCode::FAILURE, status.code);
+    });
+    ASSERT_TRUE(ret.isOk());
 }
 
 // Test Thermal->unregisterThermalChangedCallback.