Merge "[MEP] Add port index to icc logical channel open, close and trasmit APIs."
diff --git a/src/com/android/phone/PhoneInterfaceManager.java b/src/com/android/phone/PhoneInterfaceManager.java
index 38cf872..d605bdd 100755
--- a/src/com/android/phone/PhoneInterfaceManager.java
+++ b/src/com/android/phone/PhoneInterfaceManager.java
@@ -5081,10 +5081,13 @@
     @Override
     public int getDataNetworkTypeForSubscriber(int subId, String callingPackage,
             String callingFeatureId) {
-        if (!TelephonyPermissions.checkCallingOrSelfReadPhoneState(
-                mApp, subId, callingPackage, callingFeatureId,
-                "getDataNetworkTypeForSubscriber")) {
-            return TelephonyManager.NETWORK_TYPE_UNKNOWN;
+        String functionName = "getDataNetworkTypeForSubscriber";
+        if (!TelephonyPermissions.checkCallingOrSelfReadNonDangerousPhoneStateNoThrow(
+                mApp, functionName)) {
+            if (!TelephonyPermissions.checkCallingOrSelfReadPhoneState(
+                    mApp, subId, callingPackage, callingFeatureId, functionName)) {
+                return TelephonyManager.NETWORK_TYPE_UNKNOWN;
+            }
         }
 
         final long identity = Binder.clearCallingIdentity();
@@ -5106,10 +5109,13 @@
     @Override
     public int getVoiceNetworkTypeForSubscriber(int subId, String callingPackage,
             String callingFeatureId) {
-        if (!TelephonyPermissions.checkCallingOrSelfReadPhoneState(
-                mApp, subId, callingPackage, callingFeatureId,
-                "getDataNetworkTypeForSubscriber")) {
-            return TelephonyManager.NETWORK_TYPE_UNKNOWN;
+        String functionName = "getVoiceNetworkTypeForSubscriber";
+        if (!TelephonyPermissions.checkCallingOrSelfReadNonDangerousPhoneStateNoThrow(
+                mApp, functionName)) {
+            if (!TelephonyPermissions.checkCallingOrSelfReadPhoneState(
+                    mApp, subId, callingPackage, callingFeatureId, functionName)) {
+                return TelephonyManager.NETWORK_TYPE_UNKNOWN;
+            }
         }
 
         final long identity = Binder.clearCallingIdentity();
@@ -6623,18 +6629,25 @@
      * There are other factors deciding whether mobile data is actually enabled, but they are
      * not considered here. See {@link #isDataEnabled(int)} for more details.
      *
-     * Accepts either ACCESS_NETWORK_STATE, MODIFY_PHONE_STATE or carrier privileges.
+     * Accepts either READ_BASIC_PHONE_STATE, ACCESS_NETWORK_STATE, MODIFY_PHONE_STATE
+     * or carrier privileges.
      *
      * @return {@code true} if data is enabled else {@code false}
      */
     @Override
     public boolean isUserDataEnabled(int subId) {
+        String functionName = "isUserDataEnabled";
         try {
-            mApp.enforceCallingOrSelfPermission(android.Manifest.permission.ACCESS_NETWORK_STATE,
-                    null);
+            try {
+                mApp.enforceCallingOrSelfPermission(permission.READ_BASIC_PHONE_STATE,
+                        functionName);
+            } catch (Exception e) {
+                mApp.enforceCallingOrSelfPermission(permission.ACCESS_NETWORK_STATE, functionName);
+            }
         } catch (Exception e) {
             TelephonyPermissions.enforceCallingOrSelfModifyPermissionOrCarrierPrivilege(
-                    mApp, subId, "isUserDataEnabled");
+                    mApp, subId, functionName);
+
         }
 
         final long identity = Binder.clearCallingIdentity();
@@ -6664,27 +6677,39 @@
      */
     @Override
     public boolean isDataEnabled(int subId) {
+        String functionName = "isDataEnabled";
         try {
             try {
                 mApp.enforceCallingOrSelfPermission(
                         android.Manifest.permission.ACCESS_NETWORK_STATE,
-                        null);
+                        functionName);
             } catch (Exception e) {
-                mApp.enforceCallingOrSelfPermission(android.Manifest.permission.READ_PHONE_STATE,
-                        "isDataEnabled");
+                try {
+                    mApp.enforceCallingOrSelfPermission(
+                            android.Manifest.permission.READ_PHONE_STATE,
+                            functionName);
+                } catch (Exception e2) {
+                    mApp.enforceCallingOrSelfPermission(
+                            permission.READ_BASIC_PHONE_STATE, functionName);
+                }
             }
         } catch (Exception e) {
-            enforceReadPrivilegedPermission("isDataEnabled");
+            enforceReadPrivilegedPermission(functionName);
         }
 
         final long identity = Binder.clearCallingIdentity();
         try {
             int phoneId = mSubscriptionController.getPhoneId(subId);
-            if (DBG) log("isDataEnabled: subId=" + subId + " phoneId=" + phoneId);
             Phone phone = PhoneFactory.getPhone(phoneId);
             if (phone != null) {
-                boolean retVal = phone.getDataEnabledSettings().isDataEnabled();
-                if (DBG) log("isDataEnabled: subId=" + subId + " retVal=" + retVal);
+                boolean retVal;
+                if (phone.isUsingNewDataStack()) {
+                    retVal = phone.getDataNetworkController().getDataSettingsManager()
+                            .isDataEnabled();
+                } else {
+                    retVal = phone.getDataEnabledSettings().isDataEnabled();
+                }
+                if (DBG) log("isDataEnabled: " + retVal + ", subId=" + subId);
                 return retVal;
             } else {
                 if (DBG) loge("isDataEnabled: no phone subId=" + subId + " retVal=false");
@@ -6704,16 +6729,23 @@
     @Override
     public boolean isDataEnabledForReason(int subId,
             @TelephonyManager.DataEnabledReason int reason) {
+        String functionName = "isDataEnabledForReason";
         try {
-            mApp.enforceCallingOrSelfPermission(android.Manifest.permission.ACCESS_NETWORK_STATE,
-                    null);
+            try {
+                mApp.enforceCallingOrSelfPermission(
+                        android.Manifest.permission.ACCESS_NETWORK_STATE,
+                        functionName);
+            } catch (Exception e) {
+                mApp.enforceCallingOrSelfPermission(permission.READ_BASIC_PHONE_STATE,
+                        functionName);
+            }
         } catch (Exception e) {
             try {
                 mApp.enforceCallingOrSelfPermission(android.Manifest.permission.READ_PHONE_STATE,
-                        "isDataEnabledForReason");
+                        functionName);
             } catch (Exception e2) {
                 TelephonyPermissions.enforceCallingOrSelfModifyPermissionOrCarrierPrivilege(
-                        mApp, subId, "isDataEnabledForReason");
+                        mApp, subId, functionName);
             }
         }
 
@@ -8641,6 +8673,7 @@
      *
      * <p>Requires one of the following permissions:
      * {@link android.Manifest.permission#ACCESS_NETWORK_STATE},
+     * {@link android.Manifest.permission#READ_BASIC_PHONE_STATE},
      * {@link android.Manifest.permission#READ_PHONE_STATE} or that the calling app has carrier
      * privileges.
      *
@@ -8650,12 +8683,19 @@
      */
     @Override
     public boolean isDataRoamingEnabled(int subId) {
+        String functionName = "isDataRoamingEnabled";
         try {
-            mApp.enforceCallingOrSelfPermission(android.Manifest.permission.ACCESS_NETWORK_STATE,
-                    null);
+            try {
+                mApp.enforceCallingOrSelfPermission(
+                        android.Manifest.permission.ACCESS_NETWORK_STATE,
+                        functionName);
+            } catch (Exception e) {
+                mApp.enforceCallingOrSelfPermission(
+                        permission.READ_BASIC_PHONE_STATE, functionName);
+            }
         } catch (Exception e) {
             TelephonyPermissions.enforceCallingOrSelfReadPhoneStatePermissionOrCarrierPrivilege(
-                    mApp, subId, "isDataRoamingEnabled");
+                    mApp, subId, functionName);
         }
 
         boolean isEnabled = false;
diff --git a/src/com/android/services/telephony/rcs/DelegateStateTracker.java b/src/com/android/services/telephony/rcs/DelegateStateTracker.java
index 64090d5..29b8121 100644
--- a/src/com/android/services/telephony/rcs/DelegateStateTracker.java
+++ b/src/com/android/services/telephony/rcs/DelegateStateTracker.java
@@ -86,6 +86,17 @@
     @VisibleForTesting
     public static final long SUPPORT_REGISTERING_DELEGATE_STATE = 205194548;
 
+    /**
+     * For apps targeting Android T and above, support the DEREGISTERING_REASON_LOSING_PDN state
+     * on APIs, such as {@code DelegateRegistrationState#addDeregisteringFeatureTag} and
+     * {@code DelegateRegistrationState#getDeregisteringFeatureTags}
+     * @hide
+     */
+    @ChangeId
+    @EnabledAfter(targetSdkVersion = Build.VERSION_CODES.S)
+    @VisibleForTesting
+    public static final long SUPPORT_DEREGISTERING_LOSING_PDN_STATE = 201522903;
+
     public DelegateStateTracker(int subId, int uid,
             ISipDelegateConnectionStateCallback appStateCallback,
             ISipDelegate localDelegateImpl, RcsStats rcsStats) {
@@ -178,9 +189,13 @@
      */
     @Override
     public void onRegistrationStateChanged(DelegateRegistrationState registrationState) {
+        if (!mCompatChangesFactory.isChangeEnabled(SUPPORT_DEREGISTERING_LOSING_PDN_STATE, mUid)) {
+            registrationState = overrideDeregisteringStateForCompatibility(registrationState);
+        }
         if (!mCompatChangesFactory.isChangeEnabled(SUPPORT_REGISTERING_DELEGATE_STATE, mUid)) {
             registrationState = overrideRegistrationForCompatibility(registrationState);
         }
+
         if (mRegistrationStateOverride > DelegateRegistrationState.DEREGISTERED_REASON_UNKNOWN) {
             logi("onRegistrationStateChanged: overriding registered state to "
                     + mRegistrationStateOverride);
@@ -291,6 +306,43 @@
         return overriddenState.build();
     }
 
+    /**
+     * @param state The RegistrationState reported by the SipDelegate to be sent to the
+     *              IMS application .
+     * @return DEREGISTERING_REASON_PDN_CHANGE instead of DEREGISTERING_REASON_LOSING_PDN
+     * if the SUPPORT_DEREGISTERING_LOSING_PDN_STATE compat key is not enabled for the application
+     * consuming the registration change events.
+     */
+    private DelegateRegistrationState overrideDeregisteringStateForCompatibility(
+            DelegateRegistrationState state) {
+        Set<String> registeredFeatures = state.getRegisteredFeatureTags();
+        Set<String> registeringFeatures = state.getRegisteringFeatureTags();
+        DelegateRegistrationState.Builder overriddenState = new DelegateRegistrationState.Builder();
+
+        // keep other registered/registering/deregistered tags the same.
+        for (FeatureTagState dereged : state.getDeregisteredFeatureTags()) {
+            overriddenState.addDeregisteredFeatureTag(dereged.getFeatureTag(),
+                    dereged.getState());
+        }
+        overriddenState.addRegisteredFeatureTags(registeredFeatures);
+        overriddenState.addRegisteringFeatureTags(registeringFeatures);
+
+        // change DEREGISTERING_REASON_LOSING_PDN to DEREGISTERING_REASON_PDN_CHANGE
+        for (FeatureTagState dereging : state.getDeregisteringFeatureTags()) {
+            overriddenState.addDeregisteringFeatureTag(dereging.getFeatureTag(),
+                    getDeregisteringReasonForCompatibility(dereging.getState()));
+        }
+
+        return overriddenState.build();
+    }
+
+    private int getDeregisteringReasonForCompatibility(int reason) {
+        if (reason == DelegateRegistrationState.DEREGISTERING_REASON_LOSING_PDN) {
+            reason = DelegateRegistrationState.DEREGISTERING_REASON_PDN_CHANGE;
+        }
+        return reason;
+    }
+
     private void notifySipDelegateCreated() {
         try {
             mAppStateCallback.onCreated(mLocalDelegateImpl);
diff --git a/tests/src/com/android/services/telephony/rcs/DelegateStateTrackerTest.java b/tests/src/com/android/services/telephony/rcs/DelegateStateTrackerTest.java
index 0eb19e7..ffbe5ce 100644
--- a/tests/src/com/android/services/telephony/rcs/DelegateStateTrackerTest.java
+++ b/tests/src/com/android/services/telephony/rcs/DelegateStateTrackerTest.java
@@ -234,6 +234,9 @@
      * When registration states are changed in a case that an application doesn't support the new
      * 'registering' state the 'registering' state will be moved to the 'registered' state
      * as the old behavior.
+     *
+     * This method tests the case where the application doesn't support consuming the
+     * DEREGISTERING_REASON_LOSING_PDN reason.
      */
     @Test
     public void testDelegateChangingRegisteredTagsRegisteringDisable() throws Exception {
@@ -250,7 +253,7 @@
                 .addRegisteredFeatureTag(ImsSignallingUtils.ONE_TO_ONE_CHAT_TAG)
                 .addRegisteringFeatureTags(registeringTags)
                 .addDeregisteringFeatureTag(ImsSignallingUtils.FILE_TRANSFER_HTTP_TAG,
-                        DelegateRegistrationState.DEREGISTERING_REASON_PROVISIONING_CHANGE)
+                        DelegateRegistrationState.DEREGISTERING_REASON_LOSING_PDN)
                 .addDeregisteredFeatureTag(ImsSignallingUtils.GROUP_CHAT_TAG,
                         DelegateRegistrationState.DEREGISTERED_REASON_NOT_PROVISIONED)
                 .build();
@@ -259,7 +262,7 @@
         DelegateRegistrationState.Builder builder = new DelegateRegistrationState.Builder()
                 .addRegisteredFeatureTag(ImsSignallingUtils.ONE_TO_ONE_CHAT_TAG)
                 .addDeregisteringFeatureTag(ImsSignallingUtils.FILE_TRANSFER_HTTP_TAG,
-                        DelegateRegistrationState.DEREGISTERING_REASON_PROVISIONING_CHANGE)
+                        DelegateRegistrationState.DEREGISTERING_REASON_PDN_CHANGE)
                 .addDeregisteredFeatureTag(ImsSignallingUtils.GROUP_CHAT_TAG,
                         DelegateRegistrationState.DEREGISTERED_REASON_NOT_PROVISIONED);
         for (String tag : registeringTags) {
@@ -283,6 +286,9 @@
     /**
      * When registration states are changed in a case that an application supports the new
      * 'registering' state the state will be kept.
+     *
+     *  This method tests the case where the application supports consuming the
+     *  DEREGISTERING_REASON_LOSING_PDN reason.
      */
     @Test
     public void testDelegateChangingRegisteredTagsRegisteringEnable() throws Exception {
@@ -300,7 +306,7 @@
                 .addRegisteredFeatureTag(ImsSignallingUtils.ONE_TO_ONE_CHAT_TAG)
                 .addRegisteringFeatureTags(registeringTags)
                 .addDeregisteringFeatureTag(ImsSignallingUtils.FILE_TRANSFER_HTTP_TAG,
-                        DelegateRegistrationState.DEREGISTERING_REASON_PROVISIONING_CHANGE)
+                        DelegateRegistrationState.DEREGISTERING_REASON_LOSING_PDN)
                 .addDeregisteredFeatureTag(ImsSignallingUtils.GROUP_CHAT_TAG,
                         DelegateRegistrationState.DEREGISTERED_REASON_NOT_PROVISIONED)
                 .build();