[Android] Add StayActive support during commission flow for LIT (#35959)

diff --git a/examples/android/CHIPTool/app/src/main/java/com/google/chip/chiptool/provisioning/DeviceProvisioningFragment.kt b/examples/android/CHIPTool/app/src/main/java/com/google/chip/chiptool/provisioning/DeviceProvisioningFragment.kt
index 97b2576..f7049b6 100644
--- a/examples/android/CHIPTool/app/src/main/java/com/google/chip/chiptool/provisioning/DeviceProvisioningFragment.kt
+++ b/examples/android/CHIPTool/app/src/main/java/com/google/chip/chiptool/provisioning/DeviceProvisioningFragment.kt
@@ -289,7 +289,7 @@
     override fun onICDRegistrationInfoRequired() {
       Log.d(TAG, "onICDRegistrationInfoRequired")
       deviceController.updateCommissioningICDRegistrationInfo(
-        ICDRegistrationInfo.newBuilder().build()
+        ICDRegistrationInfo.newBuilder().setICDStayActiveDurationMsec(30000L).build()
       )
     }
 
diff --git a/src/controller/java/AndroidDeviceControllerWrapper.cpp b/src/controller/java/AndroidDeviceControllerWrapper.cpp
index f634f8a..fccb1ba 100644
--- a/src/controller/java/AndroidDeviceControllerWrapper.cpp
+++ b/src/controller/java/AndroidDeviceControllerWrapper.cpp
@@ -508,28 +508,44 @@
     VerifyOrReturnError(icdRegistrationInfo != nullptr, CHIP_ERROR_INVALID_ARGUMENT);
 
     JNIEnv * env = chip::JniReferences::GetInstance().GetEnvForCurrentThread();
+    if (env == nullptr)
+    {
+        ChipLogError(Controller, "Failed to retrieve JNIEnv in %s.", __func__);
+        return CHIP_ERROR_INCORRECT_STATE;
+    }
+
+    jmethodID getICDStayActiveDurationMsecMethod;
+    err = chip::JniReferences::GetInstance().FindMethod(env, icdRegistrationInfo, "getICDStayActiveDurationMsec",
+                                                        "()Ljava/lang/Long;", &getICDStayActiveDurationMsecMethod);
+    ReturnErrorOnFailure(err);
+    jobject jStayActiveMsec = env->CallObjectMethod(icdRegistrationInfo, getICDStayActiveDurationMsecMethod);
+    if (jStayActiveMsec != 0)
+    {
+        params.SetICDStayActiveDurationMsec(chip::JniReferences::GetInstance().IntegerToPrimitive(jStayActiveMsec));
+    }
+
     jmethodID getCheckInNodeIdMethod;
     err = chip::JniReferences::GetInstance().FindMethod(env, icdRegistrationInfo, "getCheckInNodeId", "()Ljava/lang/Long;",
                                                         &getCheckInNodeIdMethod);
-    VerifyOrReturnError(err == CHIP_NO_ERROR, err);
+    ReturnErrorOnFailure(err);
     jobject jCheckInNodeId = env->CallObjectMethod(icdRegistrationInfo, getCheckInNodeIdMethod);
 
     jmethodID getMonitoredSubjectMethod;
     err = chip::JniReferences::GetInstance().FindMethod(env, icdRegistrationInfo, "getMonitoredSubject", "()Ljava/lang/Long;",
                                                         &getMonitoredSubjectMethod);
-    VerifyOrReturnError(err == CHIP_NO_ERROR, err);
+    ReturnErrorOnFailure(err);
     jobject jMonitoredSubject = env->CallObjectMethod(icdRegistrationInfo, getMonitoredSubjectMethod);
 
     jmethodID getSymmetricKeyMethod;
     err =
         chip::JniReferences::GetInstance().FindMethod(env, icdRegistrationInfo, "getSymmetricKey", "()[B", &getSymmetricKeyMethod);
-    VerifyOrReturnError(err == CHIP_NO_ERROR, err);
+    ReturnErrorOnFailure(err);
     jbyteArray jSymmetricKey = static_cast<jbyteArray>(env->CallObjectMethod(icdRegistrationInfo, getSymmetricKeyMethod));
 
     jmethodID getClientTypeMethod;
     err = chip::JniReferences::GetInstance().FindMethod(env, icdRegistrationInfo, "getClientType", "()Ljava/lang/Integer;",
                                                         &getClientTypeMethod);
-    VerifyOrReturnError(err == CHIP_NO_ERROR, err);
+    ReturnErrorOnFailure(err);
     jobject jClientType = env->CallObjectMethod(icdRegistrationInfo, getClientTypeMethod);
 
     chip::NodeId checkInNodeId = chip::kUndefinedNodeId;
diff --git a/src/controller/java/src/chip/devicecontroller/ICDRegistrationInfo.java b/src/controller/java/src/chip/devicecontroller/ICDRegistrationInfo.java
index 417d147..b8fcde3 100644
--- a/src/controller/java/src/chip/devicecontroller/ICDRegistrationInfo.java
+++ b/src/controller/java/src/chip/devicecontroller/ICDRegistrationInfo.java
@@ -25,12 +25,19 @@
   @Nullable private final Long monitoredSubject;
   @Nullable private final byte[] symmetricKey;
   @Nullable private final Integer clientType;
+  @Nullable private final Long stayActiveDurationMsec;
 
   private ICDRegistrationInfo(Builder builder) {
     this.checkInNodeId = builder.checkInNodeId;
     this.monitoredSubject = builder.monitoredSubject;
     this.symmetricKey = builder.symmetricKey;
     this.clientType = builder.clientType;
+    this.stayActiveDurationMsec = builder.stayActiveDurationMsec;
+  }
+
+  /** Returns the duration period to stay active. */
+  public Long getICDStayActiveDurationMsec() {
+    return stayActiveDurationMsec;
   }
 
   /** Returns the check in node ID. */
@@ -62,6 +69,7 @@
     @Nullable private Long monitoredSubject = null;
     @Nullable private byte[] symmetricKey = null;
     @Nullable private Integer clientType = null;
+    @Nullable private Long stayActiveDurationMsec = null;
 
     private Builder() {}
 
@@ -93,6 +101,15 @@
       return this;
     }
 
+    /**
+     * Request LIT device to stay active for specific duration after commission completes, the upper
+     * bound is 30 seconds.
+     */
+    public Builder setICDStayActiveDurationMsec(Long stayActiveDurationMsec) {
+      this.stayActiveDurationMsec = stayActiveDurationMsec;
+      return this;
+    }
+
     public ICDRegistrationInfo build() {
       return new ICDRegistrationInfo(this);
     }