Adding HAL API for disabling subscription

Bug: 141018421
Test: vts on cuttlefish
Change-Id: I90ded163ddc047916c205513ab77a886ebcc48f7
Merged-In: I90ded163ddc047916c205513ab77a886ebcc48f7
diff --git a/radio/1.5/IRadio.hal b/radio/1.5/IRadio.hal
index 74ec56d..a3001fd 100644
--- a/radio/1.5/IRadio.hal
+++ b/radio/1.5/IRadio.hal
@@ -55,4 +55,45 @@
      */
     oneway setSignalStrengthReportingCriteria_1_5(int32_t serial,
             SignalThresholdInfo signalThresholdInfo, AccessNetwork accessNetwork);
+
+    /**
+     * Enable or disable UiccApplications on the SIM. If disabled:
+     *  - Modem will not register on any network.
+     *  - SIM must be PRESENT, and the IccId of the SIM must still be accessible.
+     *  - The corresponding modem stack is still functional, e.g. able to make emergency calls or
+     *    do network scan.
+     * By default if this API is not called, the uiccApplications must be enabled automatically.
+     * It must work for both single SIM and DSDS cases for UX consistency.
+     * The preference is per SIM, and must be remembered over power cycle, modem reboot, or SIM
+     * insertion / unplug.
+     *
+     * @param serial: Serial number of request.
+     * @param enable: true if to enable uiccApplications, false to disable.
+
+     * Response callback is IRadioResponse.enableUiccApplicationsResponse()
+     */
+    oneway enableUiccApplications(int32_t serial, bool enable);
+
+    /**
+     * Whether uiccApplications are enabled, or disabled.
+     *
+     * By default uiccApplications must be enabled, unless enableUiccApplications() with enable
+     * being false is called.
+     *
+     * @param serial Serial number of request.
+     *
+     * Response callback is IRadioResponse.areUiccApplicationsEnabledResponse()
+     */
+    oneway areUiccApplicationsEnabled(int32_t serial);
+
+    /**
+     * Query whether disabling and enabling UiccApplications functionality is supported. If not,
+     * calling enableUiccApplications with a different value will return
+     * RadioError:REQUEST_NOT_SUPPORTED.
+     *
+     * @param serial Serial number of request.
+     *
+     * Response callback is IRadioResponse.canToggleUiccApplicationsEnablementResponse()
+     */
+    oneway canToggleUiccApplicationsEnablement(int32_t serial);
 };
diff --git a/radio/1.5/IRadioIndication.hal b/radio/1.5/IRadioIndication.hal
index d488404..81452ab 100644
--- a/radio/1.5/IRadioIndication.hal
+++ b/radio/1.5/IRadioIndication.hal
@@ -23,4 +23,11 @@
  * Interface declaring unsolicited radio indications.
  */
 interface IRadioIndication extends @1.4::IRadioIndication {
+    /**
+     * Report change of whether uiccApplications are enabled, or disabled.
+     *
+     * @param type Type of radio indication
+     * @param enabled whether uiccApplications are enabled, or disabled
+     */
+    oneway uiccApplicationsEnablementChanged(RadioIndicationType type, bool enabled);
 };
diff --git a/radio/1.5/IRadioResponse.hal b/radio/1.5/IRadioResponse.hal
index 91dc1e0..c136ba6 100644
--- a/radio/1.5/IRadioResponse.hal
+++ b/radio/1.5/IRadioResponse.hal
@@ -32,4 +32,41 @@
      *   RadioError:RADIO_NOT_AVAILABLE
      */
     oneway setSignalStrengthReportingCriteriaResponse_1_5(RadioResponseInfo info);
+
+    /**
+     * @param info Response info struct containing response type, serial no. and error
+     *
+     * Valid errors returned:
+     *   RadioError:NONE
+     *   RadioError:SIM_ABSENT
+     *   RadioError:RADIO_NOT_AVAILABLE
+     *   RadioError:INTERNAL_ERR
+     *   RadioError:BUSY
+     *   RadioError:REQUEST_NOT_SUPPORTED
+     */
+    oneway enableUiccApplicationsResponse(RadioResponseInfo info);
+
+    /**
+     * @param info Response info struct containing response type, serial no. and error
+     * @param enabled whether Uicc applications are enabled.
+     *
+     * Valid errors returned:
+     *   RadioError:NONE
+     *   RadioError:SIM_ABSENT
+     *   RadioError:RADIO_NOT_AVAILABLE
+     *   RadioError:INTERNAL_ERR
+     *   RadioError:REQUEST_NOT_SUPPORTED
+     */
+    oneway areUiccApplicationsEnabledResponse(RadioResponseInfo info, bool enabled);
+
+    /**
+     * @param info Response info struct containing response type, serial no. and error
+     * @param canToggle whether toggling UiccApplications functionality is supported.
+     *
+     * Valid errors returned:
+     *   RadioError:NONE
+     *   RadioError:RADIO_NOT_AVAILABLE
+     *   RadioError:INTERNAL_ERR
+     */
+    oneway canToggleUiccApplicationsEnablementResponse(RadioResponseInfo info, bool canToggle);
 };
diff --git a/radio/1.5/vts/functional/radio_hidl_hal_api.cpp b/radio/1.5/vts/functional/radio_hidl_hal_api.cpp
index d173411..72e8d5e 100644
--- a/radio/1.5/vts/functional/radio_hidl_hal_api.cpp
+++ b/radio/1.5/vts/functional/radio_hidl_hal_api.cpp
@@ -276,3 +276,173 @@
           toString(radioRsp_v1_5->rspInfo.error).c_str());
     ASSERT_TRUE(CheckAnyOfErrors(radioRsp_v1_5->rspInfo.error, {RadioError::NONE}));
 }
+
+/*
+ * Test IRadio.enableUiccApplications() for the response returned.
+ */
+TEST_F(RadioHidlTest_v1_5, togglingUiccApplicationsNotSupported) {
+    serial = GetRandomSerialNumber();
+
+    radio_v1_5->canToggleUiccApplicationsEnablement(serial);
+    EXPECT_EQ(std::cv_status::no_timeout, wait());
+    EXPECT_EQ(RadioResponseType::SOLICITED, radioRsp_v1_5->rspInfo.type);
+    EXPECT_EQ(serial, radioRsp_v1_5->rspInfo.serial);
+    // No error should happen.
+    EXPECT_EQ(RadioError::NONE, radioRsp_v1_5->rspInfo.error);
+
+    // Supported case will be tested by other test cases.
+    if (radioRsp_v1_5->canToggleUiccApplicationsEnablement) return;
+
+    // Enabling UiccApplications should still work as it should be enabled by default.
+    serial = GetRandomSerialNumber();
+    radio_v1_5->enableUiccApplications(serial, true);
+    EXPECT_EQ(std::cv_status::no_timeout, wait());
+    EXPECT_EQ(RadioResponseType::SOLICITED, radioRsp_v1_5->rspInfo.type);
+    EXPECT_EQ(serial, radioRsp_v1_5->rspInfo.serial);
+    EXPECT_EQ(RadioError::NONE, radioRsp_v1_5->rspInfo.error);
+
+    // Disabling UiccApplications should return REQUEST_NOT_SUPPORTED error.
+    serial = GetRandomSerialNumber();
+    radio_v1_5->enableUiccApplications(serial, false);
+    EXPECT_EQ(std::cv_status::no_timeout, wait());
+    EXPECT_EQ(RadioResponseType::SOLICITED, radioRsp_v1_5->rspInfo.type);
+    EXPECT_EQ(serial, radioRsp_v1_5->rspInfo.serial);
+    EXPECT_EQ(RadioError::REQUEST_NOT_SUPPORTED, radioRsp_v1_5->rspInfo.error);
+
+    // Query areUiccApplicationsEnabled should return true.
+    serial = GetRandomSerialNumber();
+    radio_v1_5->areUiccApplicationsEnabled(serial);
+    EXPECT_EQ(std::cv_status::no_timeout, wait());
+    EXPECT_EQ(RadioResponseType::SOLICITED, radioRsp_v1_5->rspInfo.type);
+    EXPECT_EQ(serial, radioRsp_v1_5->rspInfo.serial);
+    EXPECT_EQ(RadioError::NONE, radioRsp_v1_5->rspInfo.error);
+    ASSERT_TRUE(radioRsp_v1_5->areUiccApplicationsEnabled);
+}
+
+/*
+ * Test IRadio.enableUiccApplications() for the response returned.
+ * For SIM ABSENT case.
+ */
+TEST_F(RadioHidlTest_v1_5, togglingUiccApplicationsSupportedSimAbsent) {
+    serial = GetRandomSerialNumber();
+
+    radio_v1_5->canToggleUiccApplicationsEnablement(serial);
+    EXPECT_EQ(std::cv_status::no_timeout, wait());
+    EXPECT_EQ(RadioResponseType::SOLICITED, radioRsp_v1_5->rspInfo.type);
+    EXPECT_EQ(serial, radioRsp_v1_5->rspInfo.serial);
+    // No error should happen.
+    EXPECT_EQ(RadioError::NONE, radioRsp_v1_5->rspInfo.error);
+    // Not supported case will be tested by togglingUiccApplicationsNotSupported test case.
+    if (!radioRsp_v1_5->canToggleUiccApplicationsEnablement) return;
+
+    // This test case only test SIM ABSENT case.
+    if (cardStatus.base.base.cardState != CardState::ABSENT) return;
+
+    // Disable Uicc applications.
+    serial = GetRandomSerialNumber();
+    radio_v1_5->enableUiccApplications(serial, false);
+    EXPECT_EQ(std::cv_status::no_timeout, wait());
+    EXPECT_EQ(RadioResponseType::SOLICITED, radioRsp_v1_5->rspInfo.type);
+    EXPECT_EQ(serial, radioRsp_v1_5->rspInfo.serial);
+    // As SIM is absent, RadioError::SIM_ABSENT should be thrown.
+    EXPECT_EQ(RadioError::SIM_ABSENT, radioRsp_v1_5->rspInfo.error);
+
+    // Query Uicc application enablement.
+    serial = GetRandomSerialNumber();
+    radio_v1_5->areUiccApplicationsEnabled(serial);
+    EXPECT_EQ(std::cv_status::no_timeout, wait());
+    EXPECT_EQ(RadioResponseType::SOLICITED, radioRsp_v1_5->rspInfo.type);
+    EXPECT_EQ(serial, radioRsp_v1_5->rspInfo.serial);
+    // As SIM is absent, RadioError::SIM_ABSENT should be thrown.
+    EXPECT_EQ(RadioError::SIM_ABSENT, radioRsp_v1_5->rspInfo.error);
+}
+
+/*
+ * Test IRadio.enableUiccApplications() for the response returned.
+ * For SIM PRESENT case.
+ */
+TEST_F(RadioHidlTest_v1_5, togglingUiccApplicationsSupportedSimPresent) {
+    serial = GetRandomSerialNumber();
+
+    radio_v1_5->canToggleUiccApplicationsEnablement(serial);
+    EXPECT_EQ(std::cv_status::no_timeout, wait());
+    EXPECT_EQ(RadioResponseType::SOLICITED, radioRsp_v1_5->rspInfo.type);
+    EXPECT_EQ(serial, radioRsp_v1_5->rspInfo.serial);
+    // No error should happen.
+    EXPECT_EQ(RadioError::NONE, radioRsp_v1_5->rspInfo.error);
+    // Not supported case will be tested by disablingUiccApplicationsNotSupported test case.
+    if (!radioRsp_v1_5->canToggleUiccApplicationsEnablement) return;
+
+    // This test case only test SIM ABSENT case.
+    if (cardStatus.base.base.cardState != CardState::PRESENT) return;
+
+    // Disable Uicc applications.
+    serial = GetRandomSerialNumber();
+    radio_v1_5->enableUiccApplications(serial, false);
+    EXPECT_EQ(std::cv_status::no_timeout, wait());
+    EXPECT_EQ(RadioResponseType::SOLICITED, radioRsp_v1_5->rspInfo.type);
+    EXPECT_EQ(serial, radioRsp_v1_5->rspInfo.serial);
+    // As SIM is present, there shouldn't be error.
+    EXPECT_EQ(RadioError::NONE, radioRsp_v1_5->rspInfo.error);
+
+    // Query Uicc application enablement.
+    serial = GetRandomSerialNumber();
+    radio_v1_5->areUiccApplicationsEnabled(serial);
+    EXPECT_EQ(std::cv_status::no_timeout, wait());
+    EXPECT_EQ(RadioResponseType::SOLICITED, radioRsp_v1_5->rspInfo.type);
+    EXPECT_EQ(serial, radioRsp_v1_5->rspInfo.serial);
+    // As SIM is present, there shouldn't be error.
+    EXPECT_EQ(RadioError::NONE, radioRsp_v1_5->rspInfo.error);
+    ASSERT_FALSE(radioRsp_v1_5->areUiccApplicationsEnabled);
+
+    // Enable Uicc applications.
+    serial = GetRandomSerialNumber();
+    radio_v1_5->enableUiccApplications(serial, true);
+    EXPECT_EQ(std::cv_status::no_timeout, wait());
+    EXPECT_EQ(RadioResponseType::SOLICITED, radioRsp_v1_5->rspInfo.type);
+    EXPECT_EQ(serial, radioRsp_v1_5->rspInfo.serial);
+    // As SIM is present, there shouldn't be error.
+    EXPECT_EQ(RadioError::NONE, radioRsp_v1_5->rspInfo.error);
+
+    // Query Uicc application enablement.
+    serial = GetRandomSerialNumber();
+    radio_v1_5->areUiccApplicationsEnabled(serial);
+    EXPECT_EQ(std::cv_status::no_timeout, wait());
+    EXPECT_EQ(RadioResponseType::SOLICITED, radioRsp_v1_5->rspInfo.type);
+    EXPECT_EQ(serial, radioRsp_v1_5->rspInfo.serial);
+    // As SIM is present, there shouldn't be error.
+    EXPECT_EQ(RadioError::NONE, radioRsp_v1_5->rspInfo.error);
+    ASSERT_TRUE(radioRsp_v1_5->areUiccApplicationsEnabled);
+}
+
+/*
+ * Test IRadio.areUiccApplicationsEnabled() for the response returned.
+ */
+TEST_F(RadioHidlTest_v1_5, areUiccApplicationsEnabled) {
+    serial = GetRandomSerialNumber();
+
+    radio_v1_5->canToggleUiccApplicationsEnablement(serial);
+    EXPECT_EQ(std::cv_status::no_timeout, wait());
+    EXPECT_EQ(RadioResponseType::SOLICITED, radioRsp_v1_5->rspInfo.type);
+    EXPECT_EQ(serial, radioRsp_v1_5->rspInfo.serial);
+    // No error should happen.
+    EXPECT_EQ(RadioError::NONE, radioRsp_v1_5->rspInfo.error);
+
+    // Not supported case will be tested by togglingUiccApplicationsNotSupported test case.
+    if (!radioRsp_v1_5->canToggleUiccApplicationsEnablement) return;
+
+    // Disable Uicc applications.
+    serial = GetRandomSerialNumber();
+    radio_v1_5->areUiccApplicationsEnabled(serial);
+    EXPECT_EQ(std::cv_status::no_timeout, wait());
+    EXPECT_EQ(RadioResponseType::SOLICITED, radioRsp_v1_5->rspInfo.type);
+    EXPECT_EQ(serial, radioRsp_v1_5->rspInfo.serial);
+
+    // If SIM is absent, RadioError::SIM_ABSENT should be thrown. Otherwise there shouldn't be any
+    // error.
+    if (cardStatus.base.base.cardState == CardState::ABSENT) {
+        EXPECT_EQ(RadioError::SIM_ABSENT, radioRsp_v1_5->rspInfo.error);
+    } else if (cardStatus.base.base.cardState == CardState::PRESENT) {
+        EXPECT_EQ(RadioError::NONE, radioRsp_v1_5->rspInfo.error);
+    }
+}
diff --git a/radio/1.5/vts/functional/radio_hidl_hal_utils_v1_5.h b/radio/1.5/vts/functional/radio_hidl_hal_utils_v1_5.h
index 683fdfc..c05359d 100644
--- a/radio/1.5/vts/functional/radio_hidl_hal_utils_v1_5.h
+++ b/radio/1.5/vts/functional/radio_hidl_hal_utils_v1_5.h
@@ -80,6 +80,12 @@
     ::android::hardware::radio::V1_4::CarrierRestrictionsWithPriority carrierRestrictionsResp;
     ::android::hardware::radio::V1_4::SimLockMultiSimPolicy multiSimPolicyResp;
 
+    // Whether toggling uicc applications operation is supported.
+    bool canToggleUiccApplicationsEnablement;
+
+    // Whether Uicc applications are enabled or not.
+    bool areUiccApplicationsEnabled;
+
     RadioResponse_v1_5(RadioHidlTest_v1_5& parent_v1_5);
     virtual ~RadioResponse_v1_5() = default;
 
@@ -524,6 +530,10 @@
 
     /* 1.5 Api */
     Return<void> setSignalStrengthReportingCriteriaResponse_1_5(const RadioResponseInfo& info);
+    Return<void> enableUiccApplicationsResponse(const RadioResponseInfo& info);
+    Return<void> areUiccApplicationsEnabledResponse(const RadioResponseInfo& info, bool enabled);
+    Return<void> canToggleUiccApplicationsEnablementResponse(const RadioResponseInfo& info,
+                                                             bool canToggle);
 };
 
 /* Callback class for radio indication */
@@ -535,6 +545,9 @@
     RadioIndication_v1_5(RadioHidlTest_v1_5& parent_v1_5);
     virtual ~RadioIndication_v1_5() = default;
 
+    /* 1.5 Api */
+    Return<void> uiccApplicationsEnablementChanged(RadioIndicationType type, bool enabled);
+
     /* 1.4 Api */
     Return<void> currentEmergencyNumberList(
             RadioIndicationType type,
diff --git a/radio/1.5/vts/functional/radio_indication.cpp b/radio/1.5/vts/functional/radio_indication.cpp
index b63b745..acffbbe 100644
--- a/radio/1.5/vts/functional/radio_indication.cpp
+++ b/radio/1.5/vts/functional/radio_indication.cpp
@@ -328,3 +328,8 @@
                                               const ::android::hardware::hidl_string& /*reason*/) {
     return Void();
 }
+
+Return<void> RadioIndication_v1_5::uiccApplicationsEnablementChanged(RadioIndicationType /*type*/,
+                                                                     bool /*enabled*/) {
+    return Void();
+}
diff --git a/radio/1.5/vts/functional/radio_response.cpp b/radio/1.5/vts/functional/radio_response.cpp
index 29a9250..78c03a9 100644
--- a/radio/1.5/vts/functional/radio_response.cpp
+++ b/radio/1.5/vts/functional/radio_response.cpp
@@ -892,4 +892,26 @@
     rspInfo = info;
     parent_v1_5.notify(info.serial);
     return Void();
-}
\ No newline at end of file
+}
+
+Return<void> RadioResponse_v1_5::enableUiccApplicationsResponse(const RadioResponseInfo& info) {
+    rspInfo = info;
+    parent_v1_5.notify(info.serial);
+    return Void();
+}
+
+Return<void> RadioResponse_v1_5::areUiccApplicationsEnabledResponse(const RadioResponseInfo& info,
+                                                                    bool enabled) {
+    rspInfo = info;
+    areUiccApplicationsEnabled = enabled;
+    parent_v1_5.notify(info.serial);
+    return Void();
+}
+
+Return<void> RadioResponse_v1_5::canToggleUiccApplicationsEnablementResponse(
+        const RadioResponseInfo& info, bool canToggle) {
+    rspInfo = info;
+    canToggleUiccApplicationsEnablement = canToggle;
+    parent_v1_5.notify(info.serial);
+    return Void();
+}