Cleanup of Video Call pause functionality.

Whether the paused videoState is available is dependent on the carrier's
implementation of the VT spec. The original VT implementation assumed
that this was stored in a system property accessed via InCall; these CLs
move this to a Call/Connection capability which will ultimately support
multisim video capable devices.

- For MCC/MNC 310/410, disable pause of ims video calls.
- For MCC/MNC 311/480, allow pause of ims video calls.
- Default for others is allow pause.

- Modified TelecomAccountRegistry to store flag indicating which accounts
allow pausing of video.  If account doesn't support video, pausing is
inherently not allowed either.
- Modified PstPhoneCapabilities notifier to add listener which calls back
to TelecomAccountRegistry#AccountEntry to notify when the video capability
has changed, triggering the AccountEntry to refresh itself accordingly.


Bug: 16680364
Bug: 19820114
Change-Id: I3840f92270100811161120dffcfe297bef7c4ea2
diff --git a/res/values-mcc310-mnc410/config.xml b/res/values-mcc310-mnc410/config.xml
new file mode 100644
index 0000000..bf89c34
--- /dev/null
+++ b/res/values-mcc310-mnc410/config.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2015 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License
+  -->
+
+<resources>
+    <bool name="support_pause_ims_video_calls" translatable="false">false</bool>
+</resources>
\ No newline at end of file
diff --git a/res/values-mcc311-mnc480/config.xml b/res/values-mcc311-mnc480/config.xml
index df95aa4..2b032d5 100755
--- a/res/values-mcc311-mnc480/config.xml
+++ b/res/values-mcc311-mnc480/config.xml
@@ -20,4 +20,5 @@
     <!-- Flag indicating if dtmf tone type is enabled -->
     <bool name="dtmf_type_enabled">true</bool>
     <bool name="support_swap_after_merge" translatable="false">false</bool>
+    <bool name="support_pause_ims_video_calls" translatable="false">true</bool>
 </resources>
diff --git a/res/values/config.xml b/res/values/config.xml
index 881762d..b207be7 100755
--- a/res/values/config.xml
+++ b/res/values/config.xml
@@ -152,4 +152,7 @@
 
     <!-- After a CDMA conference call is merged, the swap button should be displayed. -->
     <bool name="support_swap_after_merge" translatable="false">true</bool>
+
+    <!-- For IMS video over LTE calls, determines whether video pause signalling is supported. -->
+    <bool name="support_pause_ims_video_calls" translatable="false">true</bool>
 </resources>
diff --git a/src/com/android/services/telephony/PstnPhoneCapabilitiesNotifier.java b/src/com/android/services/telephony/PstnPhoneCapabilitiesNotifier.java
index 48568d3..7a2adf1 100644
--- a/src/com/android/services/telephony/PstnPhoneCapabilitiesNotifier.java
+++ b/src/com/android/services/telephony/PstnPhoneCapabilitiesNotifier.java
@@ -20,7 +20,6 @@
 import android.content.Context;
 import android.content.Intent;
 import android.content.IntentFilter;
-import android.net.Uri;
 import android.os.AsyncResult;
 import android.os.Handler;
 import android.os.Message;
@@ -42,7 +41,15 @@
 final class PstnPhoneCapabilitiesNotifier {
     private static final int EVENT_VIDEO_CAPABILITIES_CHANGED = 1;
 
+    /**
+     * Listener called when video capabilities have changed.
+     */
+    public interface Listener {
+        public void onVideoCapabilitiesChanged(boolean isVideoCapable);
+    }
+
     private final PhoneProxy mPhoneProxy;
+    private final Listener mListener;
     private Phone mPhoneBase;
 
     private final Handler mHandler = new Handler() {
@@ -72,10 +79,11 @@
     };
 
     /*package*/
-    PstnPhoneCapabilitiesNotifier(PhoneProxy phoneProxy) {
+    PstnPhoneCapabilitiesNotifier(PhoneProxy phoneProxy, Listener listener) {
         Preconditions.checkNotNull(phoneProxy);
 
         mPhoneProxy = phoneProxy;
+        mListener = listener;
 
         registerForNotifications();
 
@@ -117,14 +125,17 @@
             Log.d(this, "handleVideoCapabilitesChanged. Video capability - " + isVideoCapable);
             PhoneAccountHandle accountHandle =
                     PhoneUtils.makePstnPhoneAccountHandle(mPhoneProxy);
+
             TelecomManager telecomMgr = TelecomManager.from(mPhoneProxy.getContext());
             PhoneAccount oldPhoneAccount = telecomMgr.getPhoneAccount(accountHandle);
             PhoneAccount.Builder builder = new PhoneAccount.Builder(oldPhoneAccount);
 
             int capabilites = newCapabilities(oldPhoneAccount.getCapabilities(),
                     PhoneAccount.CAPABILITY_VIDEO_CALLING, isVideoCapable);
+
             builder.setCapabilities(capabilites);
             telecomMgr.registerPhoneAccount(builder.build());
+            mListener.onVideoCapabilitiesChanged(isVideoCapable);
         } catch (Exception e) {
             Log.d(this, "handleVideoCapabilitesChanged. Exception=" + e);
         }
diff --git a/src/com/android/services/telephony/TelecomAccountRegistry.java b/src/com/android/services/telephony/TelecomAccountRegistry.java
index 866118c..0a78180 100644
--- a/src/com/android/services/telephony/TelecomAccountRegistry.java
+++ b/src/com/android/services/telephony/TelecomAccountRegistry.java
@@ -18,6 +18,7 @@
 
 import android.content.ComponentName;
 import android.content.Context;
+import android.content.res.Configuration;
 import android.graphics.Bitmap;
 import android.graphics.BitmapFactory;
 import android.net.Uri;
@@ -53,11 +54,13 @@
     // is not supported, i.e. SubscriptionManager.INVALID_SLOT_ID or the 5th SIM in a phone.
     private final static int defaultPhoneAccountIcon =  R.drawable.ic_multi_sim;
 
-    private final class AccountEntry {
+    final class AccountEntry implements PstnPhoneCapabilitiesNotifier.Listener {
         private final Phone mPhone;
         private final PhoneAccount mAccount;
         private final PstnIncomingCallNotifier mIncomingCallNotifier;
         private final PstnPhoneCapabilitiesNotifier mPhoneCapabilitiesNotifier;
+        private boolean mIsVideoCapable;
+        private boolean mIsVideoPauseSupported;
 
         AccountEntry(Phone phone, boolean isEmergency, boolean isDummy) {
             mPhone = phone;
@@ -65,7 +68,8 @@
             Log.d(this, "Registered phoneAccount: %s with handle: %s",
                     mAccount, mAccount.getAccountHandle());
             mIncomingCallNotifier = new PstnIncomingCallNotifier((PhoneProxy) mPhone);
-            mPhoneCapabilitiesNotifier = new PstnPhoneCapabilitiesNotifier((PhoneProxy) mPhone);
+            mPhoneCapabilitiesNotifier = new PstnPhoneCapabilitiesNotifier((PhoneProxy) mPhone,
+                    this);
         }
 
         void teardown() {
@@ -101,6 +105,11 @@
             String description;
             Bitmap iconBitmap = null;
 
+            // We can only get the real slotId from the SubInfoRecord, we can't calculate the
+            // slotId from the subId or the phoneId in all instances.
+            SubscriptionInfo record =
+                    mSubscriptionManager.getActiveSubscriptionInfo(subId);
+
             if (isEmergency) {
                 label = mContext.getResources().getString(R.string.sim_label_emergency_calls);
                 description =
@@ -111,10 +120,7 @@
                 description = label = mTelephonyManager.getNetworkOperatorName();
             } else {
                 CharSequence subDisplayName = null;
-                // We can only get the real slotId from the SubInfoRecord, we can't calculate the
-                // slotId from the subId or the phoneId in all instances.
-                SubscriptionInfo record =
-                        mSubscriptionManager.getActiveSubscriptionInfo(subId);
+
                 if (record != null) {
                     subDisplayName = record.getDisplayName();
                     slotId = record.getSimSlotIndex();
@@ -149,9 +155,13 @@
                     PhoneAccount.CAPABILITY_PLACE_EMERGENCY_CALLS |
                     PhoneAccount.CAPABILITY_MULTI_USER;
 
-            if (mPhone.isVideoEnabled()) {
+            mIsVideoCapable = mPhone.isVideoEnabled();
+            if (mIsVideoCapable) {
                 capabilities |= PhoneAccount.CAPABILITY_VIDEO_CALLING;
             }
+            if (record != null) {
+                updateVideoPauseSupport(record);
+            }
 
             if (iconBitmap == null) {
                 iconBitmap = BitmapFactory.decodeResource(
@@ -179,6 +189,56 @@
         public PhoneAccountHandle getPhoneAccountHandle() {
             return mAccount != null ? mAccount.getAccountHandle() : null;
         }
+
+        /**
+         * Updates indicator for this {@link AccountEntry} to determine if the carrier supports
+         * pause/resume signalling for IMS video calls.  The carrier setting is stored in MNC/MCC
+         * configuration files.
+         *
+         * @param subscriptionInfo The subscription info.
+         */
+        private void updateVideoPauseSupport(SubscriptionInfo subscriptionInfo) {
+            // Get the configuration for the MNC/MCC specified in the current subscription info.
+            Configuration configuration = new Configuration();
+            if (subscriptionInfo.getMcc() == 0 && subscriptionInfo.getMnc() == 0) {
+                Configuration config = mContext.getResources().getConfiguration();
+                configuration.mcc = config.mcc;
+                configuration.mnc = config.mnc;
+                Log.i(this, "updateVideoPauseSupport -- no mcc/mnc for sub: " + subscriptionInfo +
+                        " using mcc/mnc from main context: " + configuration.mcc + "/" +
+                        configuration.mnc);
+            } else {
+                Log.i(this, "updateVideoPauseSupport -- mcc/mnc for sub: " + subscriptionInfo);
+
+                configuration.mcc = subscriptionInfo.getMcc();
+                configuration.mnc = subscriptionInfo.getMnc();
+            }
+
+            // Load the MNC/MCC specific configuration.
+            Context subContext = mContext.createConfigurationContext(configuration);
+            mIsVideoPauseSupported = subContext.getResources().getBoolean(
+                    R.bool.support_pause_ims_video_calls);
+        }
+
+        /**
+         * Receives callback from {@link PstnPhoneCapabilitiesNotifier} when the video capabilities
+         * have changed.
+         *
+         * @param isVideoCapable {@code true} if video is capable.
+         */
+        @Override
+        public void onVideoCapabilitiesChanged(boolean isVideoCapable) {
+            mIsVideoCapable = isVideoCapable;
+        }
+
+        /**
+         * Indicates whether this account supports pausing video calls.
+         * @return {@code true} if the account supports pausing video calls, {@code false}
+         * otherwise.
+         */
+        public boolean isVideoPauseSupported() {
+            return mIsVideoCapable && mIsVideoPauseSupported;
+        }
     }
 
     private OnSubscriptionsChangedListener mOnSubscriptionsChangedListener =
@@ -238,6 +298,22 @@
     }
 
     /**
+     * Determines if the {@link AccountEntry} associated with a {@link PhoneAccountHandle} supports
+     * pausing video calls.
+     *
+     * @param handle The {@link PhoneAccountHandle}.
+     * @return {@code True} if video pausing is supported.
+     */
+    boolean isVideoPauseSupported(PhoneAccountHandle handle) {
+        for (AccountEntry entry : mAccounts) {
+            if (entry.getPhoneAccountHandle().equals(handle)) {
+                return entry.isVideoPauseSupported();
+            }
+        }
+        return false;
+    }
+
+    /**
      * Sets up all the phone accounts for SIMs on first boot.
      */
     void setupOnBoot() {
@@ -255,6 +331,7 @@
         // because this could signal a removal or addition of a SIM in a single SIM phone.
         mTelephonyManager.listen(mPhoneStateListener, PhoneStateListener.LISTEN_SERVICE_STATE);
     }
+
     /**
      * Determines if the list of {@link AccountEntry}(s) contains an {@link AccountEntry} with a
      * specified {@link PhoneAccountHandle}.
diff --git a/src/com/android/services/telephony/TelephonyConnection.java b/src/com/android/services/telephony/TelephonyConnection.java
index f0b6049..eea079a 100644
--- a/src/com/android/services/telephony/TelephonyConnection.java
+++ b/src/com/android/services/telephony/TelephonyConnection.java
@@ -249,6 +249,12 @@
     private boolean mHasHighDefAudio;
 
     /**
+     * For video calls, indicates whether the outgoing video for the call can be paused using
+     * the {@link android.telecom.VideoProfile.VideoState#PAUSED} VideoState.
+     */
+    private boolean mIsVideoPauseSupported;
+
+    /**
      * Listeners to our TelephonyConnection specific callbacks
      */
     private final Set<TelephonyConnectionListener> mTelephonyListeners = Collections.newSetFromMap(
@@ -481,6 +487,8 @@
         newCapabilities = changeCapability(newCapabilities,
                 CAPABILITY_HIGH_DEF_AUDIO, mHasHighDefAudio);
         newCapabilities = changeCapability(newCapabilities, CAPABILITY_WIFI, mIsWifi);
+        newCapabilities = changeCapability(newCapabilities, CAPABILITY_CAN_PAUSE_VIDEO,
+                mIsVideoPauseSupported && mRemoteVideoCapable && mLocalVideoCapable);
 
         newCapabilities = applyConferenceTerminationCapabilities(newCapabilities);
 
@@ -848,6 +856,16 @@
     }
 
     /**
+     * For video calls, sets whether this connection supports pausing the outgoing video for the
+     * call using the {@link android.telecom.VideoProfile.VideoState#PAUSED} VideoState.
+     *
+     * @param isVideoPauseSupported {@code true} if pause state supported, {@code false} otherwise.
+     */
+    public void setVideoPauseSupported(boolean isVideoPauseSupported) {
+        mIsVideoPauseSupported = isVideoPauseSupported;
+    }
+
+    /**
      * 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 39dbfc1..eba3461 100644
--- a/src/com/android/services/telephony/TelephonyConnectionService.java
+++ b/src/com/android/services/telephony/TelephonyConnectionService.java
@@ -184,7 +184,7 @@
         }
 
         final TelephonyConnection connection =
-                createConnectionFor(phone, null, true /* isOutgoing */);
+                createConnectionFor(phone, null, true /* isOutgoing */, request.getAccountHandle());
         if (connection == null) {
             return Connection.createFailedConnection(
                     DisconnectCauseUtil.toTelecomDisconnectCause(
@@ -257,9 +257,9 @@
         }
 
         Connection connection =
-                createConnectionFor(phone, originalConnection, false /* isOutgoing */);
+                createConnectionFor(phone, originalConnection, false /* isOutgoing */,
+                        request.getAccountHandle());
         if (connection == null) {
-            connection = Connection.createCanceledConnection();
             return Connection.createCanceledConnection();
         } else {
             return connection;
@@ -307,7 +307,8 @@
 
         TelephonyConnection connection =
                 createConnectionFor(phone, unknownConnection,
-                        !unknownConnection.isIncoming() /* isOutgoing */);
+                        !unknownConnection.isIncoming() /* isOutgoing */,
+                        request.getAccountHandle());
 
         if (connection == null) {
             return Connection.createCanceledConnection();
@@ -367,7 +368,8 @@
     private TelephonyConnection createConnectionFor(
             Phone phone,
             com.android.internal.telephony.Connection originalConnection,
-            boolean isOutgoing) {
+            boolean isOutgoing,
+            PhoneAccountHandle phoneAccountHandle) {
         TelephonyConnection returnConnection = null;
         int phoneType = phone.getPhoneType();
         if (phoneType == TelephonyManager.PHONE_TYPE_GSM) {
@@ -380,6 +382,9 @@
         if (returnConnection != null) {
             // Listen to Telephony specific callbacks from the connection
             returnConnection.addTelephonyConnectionListener(mTelephonyConnectionListener);
+            returnConnection.setVideoPauseSupported(
+                    TelecomAccountRegistry.getInstance(this).isVideoPauseSupported(
+                            phoneAccountHandle));
         }
         return returnConnection;
     }