Merge "Primary IMEI FR70532 changes"
diff --git a/extphone/src/com/qti/extphone/ExtTelephonyManager.java b/extphone/src/com/qti/extphone/ExtTelephonyManager.java
index c6b2e75..9d74c74 100644
--- a/extphone/src/com/qti/extphone/ExtTelephonyManager.java
+++ b/extphone/src/com/qti/extphone/ExtTelephonyManager.java
@@ -29,17 +29,21 @@
 
 package com.qti.extphone;
 
-import android.util.Log;
-import android.os.Message;
+import android.content.ComponentName;
 import android.content.Context;
+import android.content.Intent;
+import android.content.ServiceConnection;
+import android.os.Message;
 import android.os.IBinder;
 import android.os.Handler;
 import android.os.RemoteException;
-import android.content.Intent;
-import android.content.ServiceConnection;
-import android.content.ComponentName;
-
 import android.telephony.ImsiEncryptionInfo;
+import android.util.Log;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.List;
 
 /**
 * ExtTelephonyManager class provides ExtTelephonyService interface to
@@ -51,16 +55,18 @@
 
     private static final String LOG_TAG = "ExtTelephonyManager";
     private static final boolean DBG = true;
-    private static Context mContext;
-    private Boolean mServiceConnected;
-    private ExtTelephonyServiceConnection mConnection;
-    private IExtPhone mExtTelephonyService = null;
-    private Handler mServiceConnectionStatusHandler = null;
-    private int mServiceConnectionStatusId;
-    private int INVALID = -1;
+    private static final int INVALID = -1;
+
     private static ExtTelephonyManager mInstance;
-    private ServiceCallback mServiceCb = null;
-    private static int mClientCount = 0;
+
+    private Context mContext;
+    private ExtTelephonyServiceConnection mConnection =
+            new ExtTelephonyServiceConnection();
+    private IExtPhone mExtTelephonyService = null;
+
+    private List<ServiceCallback> mServiceCbs =
+            Collections.synchronizedList(new ArrayList<>());
+    private AtomicBoolean mServiceConnected = new AtomicBoolean();
 
     /**
     * Constructor
@@ -68,8 +74,11 @@
     *                initiated.
     */
     public ExtTelephonyManager(Context context) {
+        if (context == null) {
+            throw new IllegalArgumentException("Context is null");
+        }
         this.mContext = context;
-        mServiceConnected = false;
+        mServiceConnected.set(false);
         log("ExtTelephonyManager() ...");
     }
 
@@ -79,7 +88,12 @@
     public static synchronized ExtTelephonyManager getInstance(Context context) {
         synchronized (ExtTelephonyManager.class) {
             if (mInstance == null) {
-                mInstance = new ExtTelephonyManager(context);
+                if (context != null) {
+                    Context appContext = context.getApplicationContext();
+                    mInstance = new ExtTelephonyManager(appContext);
+                } else {
+                    throw new IllegalArgumentException("Context is null");
+                }
             }
             return mInstance;
         }
@@ -90,12 +104,12 @@
     * @return boolean true if service is connected, false oterwise
     */
     public boolean isServiceConnected() {
-        return mServiceConnected;
+        return mServiceConnected.get();
     }
 
     public boolean isFeatureSupported(int feature) {
         boolean ret = false;
-        if (!mServiceConnected){
+        if (!isServiceConnected()) {
             Log.e(LOG_TAG, "service not connected!");
             return ret;
         }
@@ -121,29 +135,73 @@
     *                 to listen to the Result.
     */
     public boolean connectService(ServiceCallback cb) {
-        mServiceCb = cb;
-        mClientCount += 1;
-        log("Creating ExtTelephonyService. If not started yet, start ...");
-        Intent intent = new Intent();
-        intent.setComponent(new ComponentName("com.qti.phone",
-                                              "com.qti.phone.ExtTelephonyService"));
-        mConnection = new ExtTelephonyServiceConnection();
-        boolean success = mContext.bindService(intent, mConnection, Context.BIND_AUTO_CREATE);
-        log("bindService result: " + success);
+        boolean success = true;
+        if (!isServiceConnected() && mServiceCbs.isEmpty()) {
+            log("Creating ExtTelephonyService. If not started yet, start ...");
+            addServiceCallback(cb);
+            Intent intent = new Intent();
+            intent.setComponent(new ComponentName("com.qti.phone",
+                    "com.qti.phone.ExtTelephonyService"));
+            success = mContext.bindService(intent, mConnection,
+                    Context.BIND_AUTO_CREATE);
+            log("bind Service result: " + success);
+        } else {
+            addServiceCallback(cb);
+            if (isServiceConnected() && cb != null) {
+                cb.onConnected();
+            }
+        }
         return success;
     }
 
+    private void addServiceCallback(ServiceCallback cb) {
+        if (cb != null && !mServiceCbs.contains(cb)) {
+             mServiceCbs.add(cb);
+        }
+    }
+
     /**
     * Disconnect the connection with the Service.
     *
+    * @deprecated Replaced by {@link #disconnectService(ServiceCallback)}
+    *
     */
     public void disconnectService() {
-        log( "disconnectService() mClientCount="+mClientCount);
-        if (mClientCount > 0) mClientCount -= 1;
-        if (mClientCount <= 0 && mConnection != null) {
-            mContext.unbindService(mConnection);
-            mConnection = null;
+        disconnectService(null);
+    }
+
+    /**
+    * Disconnect the connection with the Service.
+    *
+    * @param serviceCallback {@link ServiceCallback} to receive
+    * service-level callbacks.
+    *
+    */
+    public void disconnectService(ServiceCallback cb) {
+        if (cb != null) {
+            if (!isServiceConnected()) {
+                cb.onDisconnected();
+            }
+            if (mServiceCbs.contains(cb)) {
+                mServiceCbs.remove(cb);
+            }
         }
+        if (isServiceConnected() && mServiceCbs.isEmpty()) {
+            mContext.unbindService(mConnection);
+        }
+    }
+
+    private void notifyConnected() {
+        for (ServiceCallback cb : mServiceCbs) {
+            cb.onConnected();
+        }
+    }
+
+    private void notifyDisconnected() {
+        for (ServiceCallback cb : mServiceCbs) {
+            cb.onDisconnected();
+        }
+        mServiceCbs.clear();
     }
 
     /**
@@ -159,19 +217,15 @@
             } else {
                 log("ExtTelephonyService connected ... ");
             }
-            mServiceConnected = true;
-            if (mServiceCb != null) {
-                mServiceCb.onConnected();
-            }
+            mServiceConnected.set(true);
+            notifyConnected();
         }
 
         public void onServiceDisconnected(ComponentName name) {
             log("The connection to the service got disconnected!");
             mExtTelephonyService = null;
-            mServiceConnected = false;
-            if (mServiceCb != null) {
-                mServiceCb.onDisconnected();
-            }
+            mServiceConnected.set(false);
+            notifyDisconnected();
         }
     }
 
@@ -183,7 +237,7 @@
     */
     public int getPropertyValueInt(String property, int def) {
         int ret = INVALID;
-        if (!mServiceConnected) {
+        if (!isServiceConnected()) {
             Log.e(LOG_TAG, "service not connected!");
             return ret;
         }
@@ -205,7 +259,7 @@
     */
     public boolean getPropertyValueBool(String property, boolean def) {
         boolean ret = def;
-        if (!mServiceConnected) {
+        if (!isServiceConnected()) {
             Log.e(LOG_TAG, "service not connected!");
             return ret;
         }
@@ -227,7 +281,7 @@
     */
     public String getPropertyValueString(String property, String def) {
         String ret = def;
-        if (!mServiceConnected) {
+        if (!isServiceConnected()) {
             Log.e(LOG_TAG, "service not connected!");
             return ret;
         }
@@ -248,7 +302,7 @@
     */
     public boolean isPrimaryCarrierSlotId(int slotId) {
         boolean ret = false;
-        if (!mServiceConnected) {
+        if (!isServiceConnected()) {
             Log.e(LOG_TAG, "service not connected!");
             return ret;
         }
@@ -268,7 +322,7 @@
     */
     public int getCurrentPrimaryCardSlotId() {
         int ret = INVALID;
-        if (!mServiceConnected) {
+        if (!isServiceConnected()) {
             Log.e(LOG_TAG, "service not connected!");
             return ret;
         }
@@ -288,7 +342,7 @@
     */
     public int getPrimaryCarrierSlotId() {
         int ret = INVALID;
-        if (!mServiceConnected) {
+        if (!isServiceConnected()) {
             Log.e(LOG_TAG, "service not connected!");
             return ret;
         }
@@ -307,7 +361,7 @@
     * @return void
     */
     public void setPrimaryCardOnSlot(int slotId) {
-        if (!mServiceConnected) {
+        if (!isServiceConnected()) {
             Log.e(LOG_TAG, "service not connected!");
             return;
         }
@@ -328,7 +382,7 @@
     */
     public boolean performIncrementalScan(int slotId) {
         boolean ret = false;
-        if (!mServiceConnected) {
+        if (!isServiceConnected()) {
             Log.e(LOG_TAG, "service not connected!");
             return ret;
         }
@@ -350,7 +404,7 @@
     */
     public boolean abortIncrementalScan(int slotId) {
         boolean ret = false;
-        if (!mServiceConnected) {
+        if (!isServiceConnected()) {
             Log.e(LOG_TAG, "service not connected!");
             return ret;
         }
@@ -372,7 +426,7 @@
     */
     public boolean isSMSPromptEnabled() {
         boolean ret = false;
-        if (!mServiceConnected) {
+        if (!isServiceConnected()) {
             Log.e(LOG_TAG, "service not connected!");
             return ret;
         }
@@ -393,7 +447,7 @@
     * Requires Permission: android.Manifest.permission.MODIFY_PHONE_STATE
     */
     public void setSMSPromptEnabled(boolean enabled) {
-        if (!mServiceConnected) {
+        if (!isServiceConnected()) {
             Log.e(LOG_TAG, "service not connected!");
             return;
         }
@@ -415,7 +469,7 @@
     */
     public void supplyIccDepersonalization(String netpin, String type,
             IDepersoResCallback callback, int phoneId) {
-        if (!mServiceConnected) {
+        if (!isServiceConnected()) {
             Log.e(LOG_TAG, "service not connected!");
             return;
         }
@@ -430,7 +484,7 @@
 
     public Token enableEndc(int slot, boolean enable, Client client) {
         Token token = null;
-        if (!mServiceConnected) {
+        if (!isServiceConnected()) {
             Log.e(LOG_TAG, "service not connected!");
             return token;
         }
@@ -445,7 +499,7 @@
 
     public Token queryNrIconType(int slot, Client client) {
         Token token = null;
-        if (!mServiceConnected) {
+        if (!isServiceConnected()) {
             Log.e(LOG_TAG, "service not connected!");
             return token;
         }
@@ -460,7 +514,7 @@
 
     public Token queryEndcStatus(int slot, Client client) {
         Token token = null;
-        if (!mServiceConnected) {
+        if (!isServiceConnected()) {
             Log.e(LOG_TAG, "service not connected!");
             return token;
         }
@@ -475,7 +529,7 @@
 
     public Token setNrConfig(int slot, NrConfig config, Client client) {
         Token token = null;
-        if (!mServiceConnected) {
+        if (!isServiceConnected()) {
             Log.e(LOG_TAG, "service not connected!");
             return token;
         }
@@ -490,7 +544,7 @@
 
     public Token queryNrConfig(int slot, Client client) {
         Token token = null;
-        if (!mServiceConnected) {
+        if (!isServiceConnected()) {
             Log.e(LOG_TAG, "service not connected!");
             return token;
         }
@@ -505,7 +559,7 @@
 
     public Token sendCdmaSms(int slot, byte[] pdu, boolean expectMore, Client client) {
         Token token = null;
-        if (!mServiceConnected) {
+        if (!isServiceConnected()) {
             Log.e(LOG_TAG, "service not connected!");
             return token;
         }
@@ -520,7 +574,7 @@
 
     public Token getQtiRadioCapability(int slotId, Client client) throws RemoteException {
         Token token = null;
-        if (!mServiceConnected) {
+        if (!isServiceConnected()) {
             Log.e(LOG_TAG, "service not connected!");
             return token;
         }
@@ -530,7 +584,7 @@
 
     public Token enable5g(int slot, Client client) {
         Token token = null;
-        if(!mServiceConnected){
+        if(!isServiceConnected()){
             Log.e(LOG_TAG, "service not connected!");
             return token;
         }
@@ -545,7 +599,7 @@
 
     public Token disable5g(int slot, Client client) {
         Token token = null;
-        if(!mServiceConnected){
+        if(!isServiceConnected()){
             Log.e(LOG_TAG, "service not connected!");
             return token;
         }
@@ -560,7 +614,7 @@
 
     public Token queryNrBearerAllocation(int slot, Client client) {
         Token token = null;
-        if(!mServiceConnected){
+        if(!isServiceConnected()){
             Log.e(LOG_TAG, "service not connected!");
             return token;
         }
@@ -576,7 +630,7 @@
     public Token setCarrierInfoForImsiEncryption(int slot, ImsiEncryptionInfo info,
             Client client) {
         Token token = null;
-        if(!mServiceConnected){
+        if(!isServiceConnected()){
             Log.e(LOG_TAG, "service not connected!");
             return token;
         }
@@ -591,7 +645,7 @@
 
     public Token enable5gOnly(int slot, Client client) {
         Token token = null;
-        if(!mServiceConnected){
+        if(!isServiceConnected()){
             Log.e(LOG_TAG, "service not connected!");
             return token;
         }
@@ -606,7 +660,7 @@
 
     public Token query5gStatus(int slot, Client client) {
         Token token = null;
-        if(!mServiceConnected){
+        if(!isServiceConnected()){
             Log.e(LOG_TAG, "service not connected!");
             return token;
         }
@@ -621,7 +675,7 @@
 
     public Token queryNrDcParam(int slot, Client client) {
         Token token = null;
-        if(!mServiceConnected){
+        if(!isServiceConnected()){
             Log.e(LOG_TAG, "service not connected!");
             return token;
         }
@@ -636,7 +690,7 @@
 
     public Token queryNrSignalStrength(int slot, Client client) {
         Token token = null;
-        if(!mServiceConnected){
+        if(!isServiceConnected()){
             Log.e(LOG_TAG, "service not connected!");
             return token;
         }
@@ -651,7 +705,7 @@
 
     public Token queryUpperLayerIndInfo(int slot, Client client) {
         Token token = null;
-        if(!mServiceConnected){
+        if(!isServiceConnected()){
             Log.e(LOG_TAG, "service not connected!");
             return token;
         }
@@ -666,7 +720,7 @@
 
     public Token query5gConfigInfo(int slot, Client client) {
         Token token = null;
-        if(!mServiceConnected){
+        if(!isServiceConnected()){
             Log.e(LOG_TAG, "service not connected!");
             return token;
         }
@@ -740,7 +794,7 @@
 
     public Client registerCallback(String packageName, IExtPhoneCallback callback) {
         Client client = null;
-        if (!mServiceConnected) {
+        if (!isServiceConnected()) {
             Log.e(LOG_TAG, "service not connected!");
             return client;
         }
@@ -754,7 +808,7 @@
     }
 
     public void unRegisterCallback(IExtPhoneCallback callback) {
-        if (!mServiceConnected) {
+        if (!isServiceConnected()) {
             Log.e(LOG_TAG, "service not connected!");
             return;
         }
diff --git a/ims/ims-ext-common/src/org/codeaurora/ims/QtiCallConstants.java b/ims/ims-ext-common/src/org/codeaurora/ims/QtiCallConstants.java
index 7113170..4394868 100644
--- a/ims/ims-ext-common/src/org/codeaurora/ims/QtiCallConstants.java
+++ b/ims/ims-ext-common/src/org/codeaurora/ims/QtiCallConstants.java
@@ -434,4 +434,10 @@
      * Type: boolean
      */
     public static String EXTRA_SMS_CALLBACK_MODE = "sms_callback_mode";
+
+    /* Call Forward service related error.
+     * This error code will be notified when user tries to
+     *  - activate CFx before register operation
+     *  - query CFNL while network does not support CFNL feature */
+    public static final int CODE_UT_CF_SERVICE_NOT_REGISTERED = 850;
 }
diff --git a/internal/src/org/codeaurora/internal/IExtTelephony.aidl b/internal/src/org/codeaurora/internal/IExtTelephony.aidl
index 711eccf..dab3de3 100644
--- a/internal/src/org/codeaurora/internal/IExtTelephony.aidl
+++ b/internal/src/org/codeaurora/internal/IExtTelephony.aidl
@@ -76,13 +76,4 @@
     * Requires permission: android.Manifest.permission.MODIFY_PHONE_STATE
     */
     boolean writeEfToIcc(int slotId, int family, int efId, in byte[] efData);
-
-    /**
-    * Check if slotId has PrimaryCarrier SIM card present or not.
-    * @param - slotId
-    * @return true or false
-    * Requires permission: android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE
-    */
-    boolean isPrimaryCarrierSlotId(int slotId);
-
 }