Add the onDeregistered with a throttling time to ImsRegistrationImplBase

This commit adds the onDeregistered API with a throttling time to ImsRegistrationImpleBase.

Bug: 412452528
Test: atest ImsServiceTest
Flag: com.android.internal.telephony.flags.support_throttle_time_for_deregistration
Change-Id: I18c31ef707ca1c21fdc27e5cd0601a73d887697f
diff --git a/core/api/system-current.txt b/core/api/system-current.txt
index 9fc2903..b77d18f 100644
--- a/core/api/system-current.txt
+++ b/core/api/system-current.txt
@@ -17874,6 +17874,7 @@
     field public static final int SUGGESTED_ACTION_TRIGGER_PLMN_BLOCK = 1; // 0x1
     field public static final int SUGGESTED_ACTION_TRIGGER_PLMN_BLOCK_WITH_TIMEOUT = 2; // 0x2
     field @FlaggedApi("com.android.internal.telephony.flags.add_rat_related_suggested_action_to_ims_registration") public static final int SUGGESTED_ACTION_TRIGGER_RAT_BLOCK = 3; // 0x3
+    field @FlaggedApi("com.android.internal.telephony.flags.support_throttle_time_for_deregistration") public static final int SUGGESTED_ACTION_TRIGGER_THROTTLE_TIME = 5; // 0x5
   }
 
   public static class RegistrationManager.RegistrationCallback {
@@ -18345,6 +18346,7 @@
     method public final void onDeregistered(android.telephony.ims.ImsReasonInfo);
     method public final void onDeregistered(@Nullable android.telephony.ims.ImsReasonInfo, int, int);
     method @FlaggedApi("com.android.internal.telephony.flags.emergency_registration_state") public final void onDeregistered(@Nullable android.telephony.ims.ImsReasonInfo, int, @NonNull android.telephony.ims.ImsRegistrationAttributes);
+    method @FlaggedApi("com.android.internal.telephony.flags.support_throttle_time_for_deregistration") public final void onDeregistered(@Nullable android.telephony.ims.ImsReasonInfo, int, @NonNull android.telephony.ims.ImsRegistrationAttributes, int);
     method public final void onDeregistered(@Nullable android.telephony.ims.ImsReasonInfo, @NonNull android.telephony.ims.SipDetails);
     method public final void onDeregistered(@Nullable android.telephony.ims.ImsReasonInfo, int, int, @NonNull android.telephony.ims.SipDetails);
     method public final void onRegistered(int);
diff --git a/telephony/java/android/telephony/ims/RegistrationManager.java b/telephony/java/android/telephony/ims/RegistrationManager.java
index 9f83da9..532f9ec 100644
--- a/telephony/java/android/telephony/ims/RegistrationManager.java
+++ b/telephony/java/android/telephony/ims/RegistrationManager.java
@@ -84,7 +84,8 @@
                 SUGGESTED_ACTION_TRIGGER_PLMN_BLOCK,
                 SUGGESTED_ACTION_TRIGGER_PLMN_BLOCK_WITH_TIMEOUT,
                 SUGGESTED_ACTION_TRIGGER_RAT_BLOCK,
-                SUGGESTED_ACTION_TRIGGER_CLEAR_RAT_BLOCKS
+                SUGGESTED_ACTION_TRIGGER_CLEAR_RAT_BLOCKS,
+                SUGGESTED_ACTION_TRIGGER_THROTTLE_TIME
     })
     @Retention(RetentionPolicy.SOURCE)
     public @interface SuggestedAction {}
@@ -136,6 +137,16 @@
     @FlaggedApi(Flags.FLAG_ADD_RAT_RELATED_SUGGESTED_ACTION_TO_IMS_REGISTRATION)
     int SUGGESTED_ACTION_TRIGGER_CLEAR_RAT_BLOCKS = 4;
 
+    /**
+     * Indicates whether to apply the registration throttling time.
+     * If this action is suggested, the value provided in should be used to delay subsequent
+     * IMS registration attempts.
+     * @hide
+     */
+    @SystemApi
+    @FlaggedApi(Flags.FLAG_SUPPORT_THROTTLE_TIME_FOR_DEREGISTRATION)
+    int SUGGESTED_ACTION_TRIGGER_THROTTLE_TIME = 5;
+
     /**@hide*/
     // Translate ImsRegistrationImplBase API to new AccessNetworkConstant because WLAN
     // and WWAN are more accurate constants.
@@ -243,6 +254,22 @@
             }
 
             @Override
+            public void onDeregisteredWithTime(ImsReasonInfo info,
+                    @SuggestedAction int suggestedAction,
+                    @ImsRegistrationImplBase.ImsRegistrationTech int imsRadioTech,
+                    int throttlingTimeSec) {
+                if (mLocalCallback == null) return;
+
+                final long callingIdentity = Binder.clearCallingIdentity();
+                try {
+                    mExecutor.execute(() -> mLocalCallback.onUnregistered(info,
+                            suggestedAction, imsRadioTech, throttlingTimeSec));
+                } finally {
+                    restoreCallingIdentity(callingIdentity);
+                }
+            }
+
+            @Override
             public void onDeregisteredWithDetails(ImsReasonInfo info,
                     @SuggestedAction int suggestedAction,
                     @ImsRegistrationImplBase.ImsRegistrationTech int imsRadioTech,
@@ -359,6 +386,26 @@
         /**
          * Notifies the framework when the IMS Provider is unregistered from the IMS network.
          *
+         * Since this callback is only required for the communication between telephony framework
+         * and ImsService, it is made hidden.
+         *
+         * @param info the {@link ImsReasonInfo} associated with why registration was disconnected.
+         * @param suggestedAction the expected behavior of radio protocol stack.
+         * @param imsRadioTech the network type on which IMS registration has failed.
+         * @param throttlingTimeSec The registration throttling time in seconds.
+         * @hide
+         */
+        public void onUnregistered(@NonNull ImsReasonInfo info,
+                @SuggestedAction int suggestedAction,
+                @ImsRegistrationImplBase.ImsRegistrationTech int imsRadioTech,
+                int throttlingTimeSec) {
+            // Default impl to keep backwards compatibility with old implementations
+            onUnregistered(info);
+        }
+
+        /**
+         * Notifies the framework when the IMS Provider is unregistered from the IMS network.
+         *
          * @param info the {@link ImsReasonInfo} associated with why registration was disconnected.
          * @param details the {@link SipDetails} related to disconnected Ims registration.
          *
diff --git a/telephony/java/android/telephony/ims/aidl/IImsRegistrationCallback.aidl b/telephony/java/android/telephony/ims/aidl/IImsRegistrationCallback.aidl
index 0a5ea17..e6b041d 100644
--- a/telephony/java/android/telephony/ims/aidl/IImsRegistrationCallback.aidl
+++ b/telephony/java/android/telephony/ims/aidl/IImsRegistrationCallback.aidl
@@ -33,6 +33,7 @@
    void onRegistered(in ImsRegistrationAttributes attr);
    void onRegistering(in ImsRegistrationAttributes attr);
    void onDeregistered(in ImsReasonInfo info, int suggestedAction, int imsRadioTech);
+   void onDeregisteredWithTime(in ImsReasonInfo info, int suggestedAction, int imsRadioTech, int throttlingTimeSec);
    void onDeregisteredWithDetails(in ImsReasonInfo info, int suggestedAction, int imsRadioTech, in SipDetails detail);
    void onTechnologyChangeFailed(int imsRadioTech, in ImsReasonInfo info);
    void onSubscriberAssociatedUriChanged(in Uri[] uris);
diff --git a/telephony/java/android/telephony/ims/stub/ImsRegistrationImplBase.java b/telephony/java/android/telephony/ims/stub/ImsRegistrationImplBase.java
index 99c26b0..6a8e9be 100644
--- a/telephony/java/android/telephony/ims/stub/ImsRegistrationImplBase.java
+++ b/telephony/java/android/telephony/ims/stub/ImsRegistrationImplBase.java
@@ -180,6 +180,14 @@
      */
     public static final int REASON_VOPS_NOT_SUPPORTED = 7;
 
+    /**
+     * The default throttling time in seconds to wait before attempting IMS registration after
+     * an IMS deregistration event. This value is used by default when a more specific throttling
+     * duration is not otherwise specified.
+     * @hide
+     */
+    public static final int DEFAULT_THROTTLE_SEC = 0;
+
     private Executor mExecutor;
 
     /**
@@ -622,6 +630,55 @@
     /**
      * Notify the framework that the device is disconnected from the IMS network.
      * <p>
+     * Note: Prior to calling {@link #onDeregistered(ImsReasonInfo,int)}, you should ensure that any
+     * changes to {@link android.telephony.ims.feature.ImsFeature} capability availability is sent
+     * to the framework.  For example,
+     * {@link android.telephony.ims.feature.MmTelFeature.MmTelCapabilities#CAPABILITY_TYPE_VIDEO}
+     * and
+     * {@link android.telephony.ims.feature.MmTelFeature.MmTelCapabilities#CAPABILITY_TYPE_VOICE}
+     * may be set to unavailable to ensure the framework knows these services are no longer
+     * available due to de-registration.  If you do not report capability changes impacted by
+     * de-registration, the framework will not know which features are no longer available as a
+     * result.
+     *
+     * @param info the {@link ImsReasonInfo} associated with why registration was disconnected.
+     * @param suggestedAction the expected behavior of radio protocol stack.
+     * @param attributes The attributes associated with the IMS registration
+     * @param throttlingTimeSec The registration throttling time in seconds.
+     * @hide This API is not part of the Android public SDK API
+     */
+    @SystemApi
+    @FlaggedApi(Flags.FLAG_SUPPORT_THROTTLE_TIME_FOR_DEREGISTRATION)
+    public final void onDeregistered(@Nullable ImsReasonInfo info,
+            @RegistrationManager.SuggestedAction int suggestedAction,
+            @NonNull ImsRegistrationAttributes attributes, int throttlingTimeSec) {
+        boolean isEmergency = isEmergency(attributes);
+        int imsRadioTech = attributes.getRegistrationTechnology();
+        if (isEmergency) {
+            updateToDisconnectedEmergencyState(info, suggestedAction, imsRadioTech);
+        } else {
+            updateToDisconnectedState(info, suggestedAction, imsRadioTech);
+        }
+        // ImsReasonInfo should never be null.
+        final ImsReasonInfo reasonInfo = (info != null) ? info : new ImsReasonInfo();
+
+        broadcastToCallbacksLocked((c) -> {
+            try {
+                if (isEmergency) {
+                    c.onDeregistered(reasonInfo, suggestedAction, imsRadioTech);
+                } else {
+                    c.onDeregisteredWithTime(
+                            reasonInfo, suggestedAction, imsRadioTech, throttlingTimeSec);
+                }
+            } catch (RemoteException e) {
+                Log.w(LOG_TAG, e + "onDeregistered() - Skipping callback.");
+            }
+        }, isEmergency);
+    }
+
+    /**
+     * Notify the framework that the device is disconnected from the IMS network.
+     * <p>
      * Note: Before calling {@link #onDeregistered(ImsReasonInfo, SipDetails)}, ImsService should
      * ensure that any changes to {@link android.telephony.ims.feature.ImsFeature} capability
      * availability is sent to the framework.