Merge "Copy the connect time on SRVCC to new connection" into mnc-dr-dev
diff --git a/src/com/android/phone/vvm/omtp/sync/VoicemailsQueryHelper.java b/src/com/android/phone/vvm/omtp/sync/VoicemailsQueryHelper.java
index b86351c..8e2c76a 100644
--- a/src/com/android/phone/vvm/omtp/sync/VoicemailsQueryHelper.java
+++ b/src/com/android/phone/vvm/omtp/sync/VoicemailsQueryHelper.java
@@ -48,7 +48,8 @@
     public static final int IS_READ = 2;
     public static final int DELETED = 3;
 
-    final static String READ_SELECTION = Voicemails.DIRTY + "=1 AND " + Voicemails.DELETED + "!=1";
+    final static String READ_SELECTION = Voicemails.DIRTY + "=1 AND "
+                + Voicemails.DELETED + "!=1 AND " + Voicemails.IS_READ + "=1";
     final static String DELETED_SELECTION = Voicemails.DELETED + "=1";
 
     private Context mContext;
diff --git a/src/com/android/services/telephony/ImsConference.java b/src/com/android/services/telephony/ImsConference.java
index 5971b00..7105b50 100644
--- a/src/com/android/services/telephony/ImsConference.java
+++ b/src/com/android/services/telephony/ImsConference.java
@@ -583,6 +583,7 @@
         ConferenceParticipantConnection connection = new ConferenceParticipantConnection(
                 parent.getOriginalConnection(), participant);
         connection.addConnectionListener(mParticipantListener);
+        connection.setConnectTimeMillis(parent.getConnectTimeMillis());
 
         if (Log.VERBOSE) {
             Log.v(this, "createConferenceParticipantConnection: %s", connection);
diff --git a/src/com/android/services/telephony/ImsConferenceController.java b/src/com/android/services/telephony/ImsConferenceController.java
index 7dcb97e..7c45657 100644
--- a/src/com/android/services/telephony/ImsConferenceController.java
+++ b/src/com/android/services/telephony/ImsConferenceController.java
@@ -18,7 +18,6 @@
 
 import com.android.internal.telephony.imsphone.ImsPhoneConnection;
 
-import android.net.Uri;
 import android.telecom.Conference;
 import android.telecom.Connection;
 import android.telecom.ConnectionService;
@@ -152,9 +151,10 @@
         List<Conferenceable> backgroundConnections = new ArrayList<>(mTelephonyConnections.size());
 
         // Loop through and collect all calls which are active or holding
-        for (Connection connection : mTelephonyConnections) {
+        for (TelephonyConnection connection : mTelephonyConnections) {
             if (Log.DEBUG) {
-                Log.d(this, "recalc - %s %s", connection.getState(), connection);
+                Log.d(this, "recalc - %s %s supportsConf? %s", connection.getState(), connection,
+                        connection.isConferenceSupported());
             }
 
             // If this connection is a member of a conference hosted on another device, it is not
@@ -166,6 +166,12 @@
                 continue;
             }
 
+            // If this connection does not support being in a conference call, then it is not
+            // conferenceable with any other connection.
+            if (!connection.isConferenceSupported()) {
+                continue;
+            }
+
             switch (connection.getState()) {
                 case Connection.STATE_ACTIVE:
                     activeConnections.add(connection);
@@ -239,8 +245,8 @@
 
             List<Connection> nonConferencedConnections =
                 new ArrayList<>(mTelephonyConnections.size());
-            for (Connection c : mTelephonyConnections) {
-                if (c.getConference() == null) {
+            for (TelephonyConnection c : mTelephonyConnections) {
+                if (c.getConference() == null && c.isConferenceSupported()) {
                     nonConferencedConnections.add(c);
                 }
             }
diff --git a/src/com/android/services/telephony/TelecomAccountRegistry.java b/src/com/android/services/telephony/TelecomAccountRegistry.java
index 3127eb8..1676032 100644
--- a/src/com/android/services/telephony/TelecomAccountRegistry.java
+++ b/src/com/android/services/telephony/TelecomAccountRegistry.java
@@ -18,10 +18,8 @@
 
 import android.content.ComponentName;
 import android.content.Context;
-import android.content.res.Configuration;
 import android.content.res.Resources;
 import android.graphics.Bitmap;
-import android.graphics.BitmapFactory;
 import android.graphics.Canvas;
 import android.graphics.PorterDuff;
 import android.graphics.drawable.Drawable;
@@ -69,6 +67,7 @@
         private final PstnPhoneCapabilitiesNotifier mPhoneCapabilitiesNotifier;
         private boolean mIsVideoCapable;
         private boolean mIsVideoPauseSupported;
+        private boolean mIsMergeCallSupported;
 
         AccountEntry(Phone phone, boolean isEmergency, boolean isDummy) {
             mPhone = phone;
@@ -172,6 +171,7 @@
             if (isCarrierInstantLetteringSupported()) {
                 capabilities |= PhoneAccount.CAPABILITY_CALL_SUBJECT;
             }
+            mIsMergeCallSupported = isCarrierMergeCallSupported();
 
             if (icon == null) {
                 // TODO: Switch to using Icon.createWithResource() once that supports tinting.
@@ -235,6 +235,17 @@
         }
 
         /**
+         * Determines from carrier config whether merging calls is supported.
+         *
+         * @return {@code true} if merging calls is supported, {@code false} otherwise.
+         */
+        private boolean isCarrierMergeCallSupported() {
+            PersistableBundle b =
+                    PhoneGlobals.getInstance().getCarrierConfigForSubId(mPhone.getSubId());
+            return b.getBoolean(CarrierConfigManager.KEY_SUPPORT_CONFERENCE_CALL_BOOL);
+        }
+
+        /**
          * Receives callback from {@link PstnPhoneCapabilitiesNotifier} when the video capabilities
          * have changed.
          *
@@ -253,6 +264,14 @@
         public boolean isVideoPauseSupported() {
             return mIsVideoCapable && mIsVideoPauseSupported;
         }
+
+        /**
+         * Indicates whether this account supports merging calls (i.e. conferencing).
+         * @return {@code true} if the account supports merging calls, {@code false} otherwise.
+         */
+        public boolean isMergeCallSupported() {
+            return mIsMergeCallSupported;
+        }
     }
 
     private OnSubscriptionsChangedListener mOnSubscriptionsChangedListener =
@@ -328,6 +347,22 @@
     }
 
     /**
+     * Determines if the {@link AccountEntry} associated with a {@link PhoneAccountHandle} supports
+     * merging calls.
+     *
+     * @param handle The {@link PhoneAccountHandle}.
+     * @return {@code True} if merging calls is supported.
+     */
+    boolean isMergeCallSupported(PhoneAccountHandle handle) {
+        for (AccountEntry entry : mAccounts) {
+            if (entry.getPhoneAccountHandle().equals(handle)) {
+                return entry.isMergeCallSupported();
+            }
+        }
+        return false;
+    }
+
+    /**
      * Sets up all the phone accounts for SIMs on first boot.
      */
     void setupOnBoot() {
diff --git a/src/com/android/services/telephony/TelephonyConferenceController.java b/src/com/android/services/telephony/TelephonyConferenceController.java
index 93b94aa..9724a32 100644
--- a/src/com/android/services/telephony/TelephonyConferenceController.java
+++ b/src/com/android/services/telephony/TelephonyConferenceController.java
@@ -27,6 +27,7 @@
 import android.net.Uri;
 import android.telecom.Conference;
 import android.telecom.ConferenceParticipant;
+import android.telecom.Conferenceable;
 import android.telecom.Connection;
 import android.telecom.DisconnectCause;
 import android.telecom.PhoneAccountHandle;
@@ -116,13 +117,15 @@
         Log.v(this, "recalculateConferenceable : %d", mTelephonyConnections.size());
 
         List<Connection> activeConnections = new ArrayList<>(mTelephonyConnections.size());
-        List<Connection> backgroundConnections = new ArrayList<>(mTelephonyConnections.size());
+        List<Connection> backgroundConnections = new ArrayList<>(
+                mTelephonyConnections.size());
 
         // Loop through and collect all calls which are active or holding
-        for (Connection connection : mTelephonyConnections) {
-            Log.d(this, "recalc - %s %s", connection.getState(), connection);
+        for (TelephonyConnection connection : mTelephonyConnections) {
+            Log.d(this, "recalc - %s %s supportsConf? %s", connection.getState(), connection,
+                    connection.isConferenceSupported());
 
-            if (!participatesInFullConference(connection)) {
+            if (connection.isConferenceSupported() && !participatesInFullConference(connection)) {
                 switch (connection.getState()) {
                     case Connection.STATE_ACTIVE:
                         activeConnections.add(connection);
@@ -158,7 +161,7 @@
             List<Connection> nonConferencedConnections =
                     new ArrayList<>(mTelephonyConnections.size());
             for (TelephonyConnection c : mTelephonyConnections) {
-                if (c.getConference() == null) {
+                if (c.isConferenceSupported() && c.getConference() == null) {
                     nonConferencedConnections.add(c);
                 }
             }
diff --git a/src/com/android/services/telephony/TelephonyConnection.java b/src/com/android/services/telephony/TelephonyConnection.java
index 0375073..50f3c38 100644
--- a/src/com/android/services/telephony/TelephonyConnection.java
+++ b/src/com/android/services/telephony/TelephonyConnection.java
@@ -318,6 +318,11 @@
     private boolean mIsVideoPauseSupported;
 
     /**
+     * Indicates whether this connection supports being a part of a conference..
+     */
+    private boolean mIsConferenceSupported;
+
+    /**
      * Listeners to our TelephonyConnection specific callbacks
      */
     private final Set<TelephonyConnectionListener> mTelephonyListeners = Collections.newSetFromMap(
@@ -1044,6 +1049,22 @@
     }
 
     /**
+     * Sets whether this connection supports conference calling.
+     * @param isConferenceSupported {@code true} if conference calling is supported by this
+     *                                         connection, {@code false} otherwise.
+     */
+    public void setConferenceSupported(boolean isConferenceSupported) {
+        mIsConferenceSupported = isConferenceSupported;
+    }
+
+    /**
+     * @return {@code true} if this connection supports merging calls into a conference.
+     */
+    public boolean isConferenceSupported() {
+        return mIsConferenceSupported;
+    }
+
+    /**
      * Whether the original connection is an IMS connection.
      * @return {@code True} if the original connection is an IMS connection, {@code false}
      *     otherwise.
diff --git a/src/com/android/services/telephony/TelephonyConnectionService.java b/src/com/android/services/telephony/TelephonyConnectionService.java
index 2cc9f03..4c33c1d 100644
--- a/src/com/android/services/telephony/TelephonyConnectionService.java
+++ b/src/com/android/services/telephony/TelephonyConnectionService.java
@@ -19,8 +19,6 @@
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
-import android.content.res.Configuration;
-import android.content.res.Resources;
 import android.net.Uri;
 import android.telecom.Connection;
 import android.telecom.ConnectionRequest;
@@ -30,7 +28,6 @@
 import android.telephony.CarrierConfigManager;
 import android.telephony.PhoneNumberUtils;
 import android.telephony.ServiceState;
-import android.telephony.SubscriptionInfo;
 import android.telephony.SubscriptionManager;
 import android.telephony.TelephonyManager;
 import android.text.TextUtils;
@@ -49,7 +46,6 @@
 
 import java.util.ArrayList;
 import java.util.List;
-import java.util.Objects;
 import java.util.regex.Pattern;
 
 /**
@@ -445,6 +441,9 @@
             returnConnection.setVideoPauseSupported(
                     TelecomAccountRegistry.getInstance(this).isVideoPauseSupported(
                             phoneAccountHandle));
+            returnConnection.setConferenceSupported(
+                    TelecomAccountRegistry.getInstance(this).isMergeCallSupported(
+                            phoneAccountHandle));
         }
         return returnConnection;
     }