Merge 645433a432418dfe65be86ad66b946ebb39f51c6 on remote branch

Change-Id: Ie9a9e2a60f50a240aee9475af4e778a2833f532e
diff --git a/ims/ims-ext-common/src/org/codeaurora/ims/ImsArControllerBase.java b/ims/ims-ext-common/src/org/codeaurora/ims/ImsArControllerBase.java
new file mode 100644
index 0000000..de4c3b1
--- /dev/null
+++ b/ims/ims-ext-common/src/org/codeaurora/ims/ImsArControllerBase.java
@@ -0,0 +1,79 @@
+/*
+ * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved.
+ * SPDX-License-Identifier: BSD-3-Clause-Clear.
+ */
+
+package org.codeaurora.ims;
+
+import android.content.Context;
+import android.os.RemoteException;
+import org.codeaurora.ims.internal.IImsArListener;
+import org.codeaurora.ims.internal.IImsArController;
+import org.codeaurora.ims.utils.QtiImsExtUtils;
+
+import java.util.concurrent.CompletionException;
+import java.util.concurrent.Executor;
+
+
+public abstract class ImsArControllerBase {
+    public final class ArBinder extends IImsArController.Stub {
+
+        @Override
+        public void setListener(
+                IImsArListener listener) throws RemoteException {
+            QtiImsExtUtils.executeMethodAsync(() -> {
+                    try {
+                        ImsArControllerBase.this.onSetListener(listener);
+                    } catch (RemoteException e) {
+                        throw new CompletionException(e);
+                    }},
+                    "setListener", mExecutor,
+                    QtiImsExtUtils.MODIFY_PHONE_STATE, mContext);
+        }
+
+        @Override
+        public void enableArMode(String cameraId) throws RemoteException {
+            QtiImsExtUtils.executeMethodAsync(() ->
+                    ImsArControllerBase.this.onEnableArMode(cameraId),
+                    "enableArMode", mExecutor, QtiImsExtUtils.MODIFY_PHONE_STATE,
+                    mContext);
+        }
+
+        @Override
+        public void setLocalRenderingDelay(int delay) throws RemoteException {
+           QtiImsExtUtils.executeMethodAsync(() ->
+                    ImsArControllerBase.this.onSetLocalRenderingDelay(delay),
+                    "setLocalRenderingDelay", mExecutor,
+                    QtiImsExtUtils.MODIFY_PHONE_STATE, mContext);
+        }
+    }
+
+    private IImsArController mBinder;
+    private Executor mExecutor;
+    private Context mContext;
+
+    public IImsArController getBinder() {
+        if (mBinder == null) {
+            mBinder = new ArBinder();
+        }
+        return mBinder;
+    }
+
+    public ImsArControllerBase(Executor executor, Context context) {
+        mExecutor = executor;
+        mContext = context;
+    }
+
+    protected void onSetListener(
+            IImsArListener listener) throws RemoteException {
+        //no-op
+    }
+
+    protected void onEnableArMode(String cameraId){
+        //no-op
+    }
+
+    protected void onSetLocalRenderingDelay(int delay) {
+        //no-op
+    }
+}
diff --git a/ims/ims-ext-common/src/org/codeaurora/ims/ImsArListenerBase.java b/ims/ims-ext-common/src/org/codeaurora/ims/ImsArListenerBase.java
new file mode 100644
index 0000000..c4c9ae2
--- /dev/null
+++ b/ims/ims-ext-common/src/org/codeaurora/ims/ImsArListenerBase.java
@@ -0,0 +1,59 @@
+/*
+ * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved.
+ * SPDX-License-Identifier: BSD-3-Clause-Clear.
+ */
+
+package org.codeaurora.ims;
+
+import org.codeaurora.ims.internal.IImsArListener;
+import android.view.Surface;
+
+public abstract class ImsArListenerBase {
+
+    private final class ArListener extends IImsArListener.Stub {
+
+        public void onRecordingSurfaceChanged(int phoneId, Surface surface,
+                int width, int height, String cameraId) {
+            ImsArListenerBase.this.
+                    onRecordingSurfaceChanged(phoneId, surface, width, height, cameraId);
+        }
+
+        public void onRecorderFrameRateChanged(int phoneId, int rate, String cameraId) {
+            ImsArListenerBase.this.onRecorderFrameRateChanged(phoneId, rate, cameraId);
+        }
+
+        public void onRecordingEnabled(int phoneId, String cameraId) {
+            ImsArListenerBase.this.onRecordingEnabled(phoneId, cameraId);
+        }
+
+        public void onRecordingDisabled(int phoneId, String cameraId) {
+            ImsArListenerBase.this.onRecordingDisabled(phoneId, cameraId);
+        }
+    }
+
+    private ArListener mListener;
+
+    public IImsArListener getBinder() {
+        if (mListener == null) {
+            mListener = new ArListener();
+        }
+        return mListener;
+    }
+
+    protected void onRecordingSurfaceChanged(int phoneId, Surface surface,
+            int width, int height, String cameraId){
+        // no-op
+    }
+
+    protected void onRecorderFrameRateChanged(int phoneId, int rate, String cameraId) {
+        // no-op
+    }
+
+    protected void onRecordingEnabled(int phoneId, String cameraId) {
+        // no-op
+    }
+
+    protected void onRecordingDisabled(int phoneId, String cameraId) {
+        // no-op
+    }
+}
diff --git a/ims/ims-ext-common/src/org/codeaurora/ims/ImsArManager.java b/ims/ims-ext-common/src/org/codeaurora/ims/ImsArManager.java
new file mode 100644
index 0000000..1011005
--- /dev/null
+++ b/ims/ims-ext-common/src/org/codeaurora/ims/ImsArManager.java
@@ -0,0 +1,89 @@
+/*
+ * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved.
+ * SPDX-License-Identifier: BSD-3-Clause-Clear.
+ */
+
+package org.codeaurora.ims;
+
+import android.os.RemoteException;
+import org.codeaurora.ims.internal.IImsArController;
+import org.codeaurora.ims.internal.IImsArListener;
+import android.util.Log;
+
+public class ImsArManager {
+    private static final String LOG_TAG = "ImsArManager";
+
+    private QtiImsExtManager mQtiImsExtMgr;
+    private volatile IImsArController mInterface;
+    private int mPhoneId;
+
+    ImsArManager(int phoneId, QtiImsExtManager imsExtMgr) {
+        mPhoneId = phoneId;
+        mQtiImsExtMgr = imsExtMgr;
+        mQtiImsExtMgr.addCleanupListener(()->{mInterface = null;});
+    }
+
+    private IImsArController getBinder() throws QtiImsException {
+        IImsArController intf = mInterface;
+        if (intf != null) {
+            return intf;
+        }
+        mQtiImsExtMgr.validateInvariants(mPhoneId);
+        intf = mQtiImsExtMgr.getArController(mPhoneId);
+        if (intf == null) {
+            Log.e(LOG_TAG, "mInterface is NULL");
+            throw new QtiImsException("Remote Interface is NULL");
+        }
+        mInterface = intf;
+        return intf;
+    }
+
+    /**
+     * Used by client to set listener for Ar call
+     * in vendor. Current implementation doesn't allow
+     * to set the listener as null and lower layer
+     * would overwrite the previous listener if this
+     * API is invoked again.
+     */
+    public void setListener(ImsArListenerBase listener)
+            throws QtiImsException {
+        mQtiImsExtMgr.validateInvariants(mPhoneId);
+        if (listener == null) {
+            Log.e(LOG_TAG, "listener is NULL");
+            throw new QtiImsException("Listener is NULL");
+        }
+        try {
+            getBinder().setListener(listener.getBinder());
+        }
+        catch (RemoteException e) {
+            throw new QtiImsException("Remote ImsService setListener : " + e);
+        }
+    }
+
+    /**
+     * Used by client to start/stop AR call.
+     * cameraId is null to stop AR. cameraId is not null to
+     * start AR with front/rear camera.
+     */
+    public void enableArMode(String cameraId) throws QtiImsException {
+        mQtiImsExtMgr.validateInvariants(mPhoneId);
+        try {
+            getBinder().enableArMode(cameraId);
+        } catch (RemoteException e) {
+            throw new QtiImsException("Remote ImsService enableArMode: " + e);
+        }
+    }
+
+    /**
+     * Used by client to set the delay of local rendering.
+     * The delay is measured in millisecond.
+     */
+    public void setLocalRenderingDelay(int delay) throws QtiImsException {
+        mQtiImsExtMgr.validateInvariants(mPhoneId);
+        try {
+            getBinder().setLocalRenderingDelay(delay);
+        } catch (RemoteException e) {
+            throw new QtiImsException("Remote ImsService setLocalRenderingDelay : " + e);
+        }
+    }
+}
diff --git a/ims/ims-ext-common/src/org/codeaurora/ims/QtiImsExtBase.java b/ims/ims-ext-common/src/org/codeaurora/ims/QtiImsExtBase.java
index fdfeac6..6ae84a1 100644
--- a/ims/ims-ext-common/src/org/codeaurora/ims/QtiImsExtBase.java
+++ b/ims/ims-ext-common/src/org/codeaurora/ims/QtiImsExtBase.java
@@ -39,6 +39,7 @@
 import org.codeaurora.ims.internal.ICrsCrbtController;
 import org.codeaurora.ims.internal.IQtiImsExt;
 import org.codeaurora.ims.internal.IQtiImsExtListener;
+import org.codeaurora.ims.internal.IImsArController;
 import org.codeaurora.ims.internal.IImsMultiIdentityInterface;
 import org.codeaurora.ims.internal.IImsScreenShareController;
 import org.codeaurora.ims.utils.QtiImsExtUtils;
@@ -309,6 +310,14 @@
                     QtiImsExtUtils.READ_PHONE_STATE, mContext);
         }
 
+        @Override
+        public IImsArController getArController(int phoneId)
+                throws RemoteException {
+            return QtiImsExtUtils.executeMethodAsyncForResult(() ->
+                    QtiImsExtBase.this.onGetArController(phoneId),
+                    "getArController", mExecutor,
+                    QtiImsExtUtils.MODIFY_PHONE_STATE, mContext);
+        }
     };
 
     private QtiImsExtBinder mQtiImsExtBinder;
@@ -454,4 +463,9 @@
             IQtiImsExtListener listener) {
         // no-op
     }
+
+    protected IImsArController onGetArController(int phoneId) {
+        // no-op
+        return null;
+    }
 }
diff --git a/ims/ims-ext-common/src/org/codeaurora/ims/QtiImsExtManager.java b/ims/ims-ext-common/src/org/codeaurora/ims/QtiImsExtManager.java
index 8e70265..c649731 100644
--- a/ims/ims-ext-common/src/org/codeaurora/ims/QtiImsExtManager.java
+++ b/ims/ims-ext-common/src/org/codeaurora/ims/QtiImsExtManager.java
@@ -45,6 +45,7 @@
 import org.codeaurora.ims.internal.ICrsCrbtController;
 import org.codeaurora.ims.internal.IQtiImsExt;
 import org.codeaurora.ims.internal.IQtiImsExtListener;
+import org.codeaurora.ims.internal.IImsArController;
 import org.codeaurora.ims.internal.IImsMultiIdentityInterface;
 import org.codeaurora.ims.internal.IImsScreenShareController;
 import org.codeaurora.ims.utils.QtiImsExtUtils;
@@ -475,4 +476,22 @@
             throw new QtiImsException("Remote ImsService sendVosActionInfo: " + e);
         }
     }
+
+    public ImsArManager createImsArManager(int phoneId)
+            throws QtiImsException {
+        validateInvariants(phoneId);
+        return new ImsArManager(phoneId, this);
+    }
+
+    /*package private*/
+    IImsArController getArController(int phoneId)
+            throws QtiImsException {
+        validateInvariants(phoneId);
+        try {
+            return mQtiImsExt.getArController(phoneId);
+        } catch(RemoteException e) {
+            throw new QtiImsException("Failed to retrieve ARInterface : " + e);
+        }
+    }
+
 }
diff --git a/ims/ims-ext-common/src/org/codeaurora/ims/internal/IImsArController.aidl b/ims/ims-ext-common/src/org/codeaurora/ims/internal/IImsArController.aidl
new file mode 100644
index 0000000..a63673d
--- /dev/null
+++ b/ims/ims-ext-common/src/org/codeaurora/ims/internal/IImsArController.aidl
@@ -0,0 +1,35 @@
+/*
+ * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved.
+ * SPDX-License-Identifier: BSD-3-Clause-Clear.
+ */
+
+package org.codeaurora.ims.internal;
+
+import org.codeaurora.ims.internal.IImsArListener;
+
+/**
+ * Used by client application to communicate with vendor code
+ * {@hide}
+ */
+oneway interface IImsArController {
+    /**
+     * Used by client to register call back listener with vendor for
+     * camera parameters and recording surface updates.
+     * @param listener call back listener
+     */
+    void setListener(in IImsArListener listener);
+
+    /**
+     * Used by client for start/stop AR call
+     * cameraId is null to stop AR. cameraId is not null to
+     * start AR with front/rear camera.
+     * @param cameraId camera id
+     */
+    void enableArMode(String cameraId);
+
+    /**
+     * Used by client for set the delay of local rendering
+     * @param delay - the delay is measured in millisecond
+     */
+    void setLocalRenderingDelay(int delay);
+}
diff --git a/ims/ims-ext-common/src/org/codeaurora/ims/internal/IImsArListener.aidl b/ims/ims-ext-common/src/org/codeaurora/ims/internal/IImsArListener.aidl
new file mode 100644
index 0000000..461f97f
--- /dev/null
+++ b/ims/ims-ext-common/src/org/codeaurora/ims/internal/IImsArListener.aidl
@@ -0,0 +1,53 @@
+/*
+ * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved.
+ * SPDX-License-Identifier: BSD-3-Clause-Clear.
+ */
+
+package org.codeaurora.ims.internal;
+
+import android.view.Surface;
+
+/**
+ * Used by client application to get the result from lower layer by
+ * communicating with vendor.
+ * {@hide}
+ */
+oneway interface IImsArListener {
+
+   /*
+    * Implemented by the AR call SDK. Used by vendor to propagate
+    * updated surface to the client
+    * @param phoneId - Denotes the phoneId
+    * @param surface - Updated recording surface from VTLib
+    * @param width - Updated width for AR call SDK
+    * @param height - Updated height for AR call SDK
+    * @param cameraId - camera Id for AR call.
+    */
+    void onRecordingSurfaceChanged(int phoneId, in Surface surface,
+            int width, int height, String cameraId);
+
+    /*
+     * Implemented by the AR call SDK. Used by vendor to propagate
+     * update fps to client.
+     * @param phoneId - Denotes the phoneId
+     * @param rate - fps.
+     * @param cameraId - camera Id for AR call.
+     */
+    void onRecorderFrameRateChanged(int phoneId, int rate, String cameraId);
+
+    /*
+     * Implemented by the AR call SDK. Used by vendor to notify AR SDK
+     * to start recording.
+     * @param phoneId - Denotes the phoneId
+     * @param cameraId - camera Id for AR call.
+     */
+    void onRecordingEnabled(int phoneId, String cameraId);
+
+    /*
+     * Implemented by the AR call SDK. Used by vendor to notify AR SDK
+     * to stop recording.
+     * @param phoneId - Denotes the phoneId
+     * @param cameraId - camera Id for AR call.
+     */
+    void onRecordingDisabled(int phoneId, String cameraId);
+}
diff --git a/ims/ims-ext-common/src/org/codeaurora/ims/internal/IQtiImsExt.aidl b/ims/ims-ext-common/src/org/codeaurora/ims/internal/IQtiImsExt.aidl
index 12caa31..2fa6561 100644
--- a/ims/ims-ext-common/src/org/codeaurora/ims/internal/IQtiImsExt.aidl
+++ b/ims/ims-ext-common/src/org/codeaurora/ims/internal/IQtiImsExt.aidl
@@ -35,6 +35,7 @@
 import android.os.Bundle;
 import org.codeaurora.ims.internal.ICrsCrbtController;
 import org.codeaurora.ims.internal.IQtiImsExtListener;
+import org.codeaurora.ims.internal.IImsArController;
 import org.codeaurora.ims.internal.IImsMultiIdentityInterface;
 import org.codeaurora.ims.internal.IImsScreenShareController;
 import org.codeaurora.ims.VosActionInfo;
@@ -391,4 +392,10 @@
      */
     oneway void sendVosActionInfo(int phoneId, in VosActionInfo vosActionInfo,
         IQtiImsExtListener listener);
+
+   /**
+    * Returns the IImsArInterface IBinder
+    */
+    IImsArController getArController(int phoneId);
+
 }