Merge "Fixing Google Voice to work with new incallui" into klp-dev
diff --git a/common/src/com/android/services/telephony/common/Call.java b/common/src/com/android/services/telephony/common/Call.java
index 994d9d2..4c68913 100644
--- a/common/src/com/android/services/telephony/common/Call.java
+++ b/common/src/com/android/services/telephony/common/Call.java
@@ -57,6 +57,20 @@
         public static final int ONHOLD = 6;         /* An active phone call placed on hold */
         public static final int DISCONNECTED = 7;   /* State after a call disconnects */
         public static final int CONFERENCED = 8;     /* Call part of a conference call */
+
+        public static boolean isConnected(int state) {
+            switch(state) {
+                case ACTIVE:
+                case INCOMING:
+                case CALL_WAITING:
+                case DIALING:
+                case ONHOLD:
+                case CONFERENCED:
+                    return true;
+                default:
+            }
+            return false;
+        }
     }
 
     /**
@@ -174,6 +188,12 @@
     // List of call Ids for for this call.  (Used for managing conference calls).
     private SortedSet<Integer> mChildCallIds = Sets.newSortedSet();
 
+    // Gateway number used to dial this call
+    private String mGatewayNumber;
+
+    // Gateway service package name
+    private String mGatewayPackage;
+
     public Call(int callId) {
         mCallId = callId;
     }
@@ -278,6 +298,22 @@
         return mChildCallIds.size() >= 2;
     }
 
+    public String getGatewayNumber() {
+        return mGatewayNumber;
+    }
+
+    public void setGatewayNumber(String number) {
+        mGatewayNumber = number;
+    }
+
+    public String getGatewayPackage() {
+        return mGatewayPackage;
+    }
+
+    public void setGatewayPackage(String packageName) {
+        mGatewayPackage = packageName;
+    }
+
     /**
      * Parcelable implementation
      */
@@ -294,6 +330,8 @@
         dest.writeInt(getCapabilities());
         dest.writeLong(getConnectTime());
         dest.writeIntArray(Ints.toArray(mChildCallIds));
+        dest.writeString(getGatewayNumber());
+        dest.writeString(getGatewayPackage());
     }
 
     /**
@@ -310,6 +348,8 @@
         mCapabilities = in.readInt();
         mConnectTime = in.readLong();
         mChildCallIds.addAll(Ints.asList(in.createIntArray()));
+        mGatewayNumber = in.readString();
+        mGatewayPackage = in.readString();
     }
 
     @Override
@@ -336,9 +376,19 @@
 
     @Override
     public String toString() {
+        return toString(true);
+    }
+
+    public String toString(boolean safe) {
         StringBuffer buffer = new StringBuffer();
         buffer.append("callId: ");
         buffer.append(mCallId);
+        if (!safe) {
+            buffer.append(", number: ");
+            buffer.append(mNumber);
+            buffer.append(", name: ");
+            buffer.append(mCnapName);
+        }
         buffer.append(", state: ");
         buffer.append(STATE_MAP.get(mState));
         buffer.append(", disconnect_cause: ");
@@ -349,8 +399,14 @@
         final long duration = System.currentTimeMillis() - getConnectTime();
         buffer.append(", elapsedTime: ");
         buffer.append(DateUtils.formatElapsedTime(duration / 1000));
+
         buffer.append(", childCalls: ");
         buffer.append(mChildCallIds.toString());
+        buffer.append(", gateway: ");
+        if (!safe) {
+            buffer.append(mGatewayNumber);
+        }
+        buffer.append(" [").append(mGatewayPackage).append("]");
 
         return buffer.toString();
     }
diff --git a/common/src/com/android/services/telephony/common/ICallHandlerService.aidl b/common/src/com/android/services/telephony/common/ICallHandlerService.aidl
index 4b6f913..df2e2de 100644
--- a/common/src/com/android/services/telephony/common/ICallHandlerService.aidl
+++ b/common/src/com/android/services/telephony/common/ICallHandlerService.aidl
@@ -31,7 +31,7 @@
 oneway interface ICallHandlerService {
 
     /**
-     * Hands a command interface to the CallMonitorService through which
+     * Hands a command interface to the CallHandlerService through which
      * the call monitor can control the phone calls.
      */
     void setCallCommandService(ICallCommandService callCommandService);
diff --git a/src/com/android/phone/CallCard.java b/src/com/android/phone/CallCard.java
index fcef7f3..22215c0 100644
--- a/src/com/android/phone/CallCard.java
+++ b/src/com/android/phone/CallCard.java
@@ -101,14 +101,6 @@
     /** Secondary "call info" block (the background "on hold" call) */
     private ViewStub mSecondaryCallInfo;
 
-    /**
-     * Container for both provider info and call state. This will take care of showing/hiding
-     * animation for those views.
-     */
-    private ViewGroup mSecondaryInfoContainer;
-    private ViewGroup mProviderInfo;
-    private TextView mProviderLabel;
-    private TextView mProviderAddress;
 
     // "Call state" widgets
     private TextView mCallStateLabel;
@@ -217,10 +209,6 @@
         mPrimaryCallInfo = (ViewGroup) findViewById(R.id.primary_call_info);
         mPrimaryCallBanner = (ViewGroup) findViewById(R.id.primary_call_banner);
 
-        mSecondaryInfoContainer = (ViewGroup) findViewById(R.id.secondary_info_container);
-        mProviderInfo = (ViewGroup) findViewById(R.id.providerInfo);
-        mProviderLabel = (TextView) findViewById(R.id.providerLabel);
-        mProviderAddress = (TextView) findViewById(R.id.providerAddress);
         mCallStateLabel = (TextView) findViewById(R.id.callStateLabel);
         mElapsedTime = (TextView) findViewById(R.id.elapsedTime);
 
@@ -418,8 +406,6 @@
     private void updateAlreadyDisconnected(CallManager cm) {
         // For the foreground call, we manually set up every component based on previous state.
         mPrimaryCallInfo.setVisibility(View.VISIBLE);
-        mSecondaryInfoContainer.setLayoutTransition(null);
-        mProviderInfo.setVisibility(View.GONE);
         mCallStateLabel.setVisibility(View.VISIBLE);
         mCallStateLabel.setText(mContext.getString(R.string.card_title_call_ended));
         mElapsedTime.setVisibility(View.VISIBLE);
@@ -829,8 +815,7 @@
         final InCallUiState inCallUiState = mApplication.inCallUiState;
         if (DBG) {
             log("==> callStateLabel: '" + callStateLabel
-                    + "', bluetoothIconId = " + bluetoothIconId
-                    + ", providerInfoVisible = " + inCallUiState.providerInfoVisible);
+                    + "', bluetoothIconId = " + bluetoothIconId);
         }
 
         // Animation will be done by mCallerDetail's LayoutTransition, but in some cases, we don't
@@ -841,22 +826,6 @@
                 || state == Call.State.DISCONNECTING
                 || state == Call.State.DISCONNECTED);
         LayoutTransition layoutTransition = null;
-        if (skipAnimation) {
-            // Evict LayoutTransition object to skip animation.
-            layoutTransition = mSecondaryInfoContainer.getLayoutTransition();
-            mSecondaryInfoContainer.setLayoutTransition(null);
-        }
-
-        if (inCallUiState.providerInfoVisible) {
-            mProviderInfo.setVisibility(View.VISIBLE);
-            mProviderLabel.setText(context.getString(R.string.calling_via_template,
-                    inCallUiState.providerLabel));
-            mProviderAddress.setText(inCallUiState.providerAddress);
-
-            mInCallScreen.requestRemoveProviderInfoWithDelay();
-        } else {
-            mProviderInfo.setVisibility(View.GONE);
-        }
 
         if (!TextUtils.isEmpty(callStateLabel)) {
             mCallStateLabel.setVisibility(View.VISIBLE);
@@ -881,10 +850,6 @@
                 mCallStateLabel.setGravity(Gravity.END);
             }
         }
-        if (skipAnimation) {
-            // Restore LayoutTransition object to recover animation.
-            mSecondaryInfoContainer.setLayoutTransition(layoutTransition);
-        }
 
         // ...and update the elapsed time widget too.
         switch (state) {
diff --git a/src/com/android/phone/CallController.java b/src/com/android/phone/CallController.java
index 7b889de..1b19d9a 100644
--- a/src/com/android/phone/CallController.java
+++ b/src/com/android/phone/CallController.java
@@ -20,6 +20,7 @@
 import com.android.internal.telephony.Phone;
 import com.android.internal.telephony.PhoneConstants;
 import com.android.internal.telephony.TelephonyCapabilities;
+import com.android.phone.CallGatewayManager.RawGatewayInfo;
 import com.android.phone.Constants.CallStatusCode;
 import com.android.phone.InCallUiState.InCallScreenMode;
 import com.android.phone.OtaUtils.CdmaOtaScreenState;
@@ -69,9 +70,10 @@
     /** The singleton CallController instance. */
     private static CallController sInstance;
 
-    private PhoneGlobals mApp;
-    private CallManager mCM;
-    private CallLogger mCallLogger;
+    final private PhoneGlobals mApp;
+    final private CallManager mCM;
+    final private CallLogger mCallLogger;
+    final private CallGatewayManager mCallGatewayManager;
 
     /** Helper object for emergency calls in some rare use cases.  Created lazily. */
     private EmergencyCallHelper mEmergencyCallHelper;
@@ -102,10 +104,11 @@
      * PhoneApp's public "callController" field, which is why there's no
      * getInstance() method here.
      */
-    /* package */ static CallController init(PhoneGlobals app, CallLogger callLogger) {
+    /* package */ static CallController init(PhoneGlobals app, CallLogger callLogger,
+            CallGatewayManager callGatewayManager) {
         synchronized (CallController.class) {
             if (sInstance == null) {
-                sInstance = new CallController(app, callLogger);
+                sInstance = new CallController(app, callLogger, callGatewayManager);
             } else {
                 Log.wtf(TAG, "init() called multiple times!  sInstance = " + sInstance);
             }
@@ -117,11 +120,13 @@
      * Private constructor (this is a singleton).
      * @see init()
      */
-    private CallController(PhoneGlobals app, CallLogger callLogger) {
+    private CallController(PhoneGlobals app, CallLogger callLogger,
+            CallGatewayManager callGatewayManager) {
         if (DBG) log("CallController constructor: app = " + app);
         mApp = app;
         mCM = app.mCM;
         mCallLogger = callLogger;
+        mCallGatewayManager = callGatewayManager;
     }
 
     @Override
@@ -243,15 +248,6 @@
         // by the PhoneUtils phone state change handler.)
         mApp.setRestoreMuteOnInCallResume(false);
 
-        // If a provider is used, extract the info to build the
-        // overlay and route the call.  The overlay will be
-        // displayed when the InCallScreen becomes visible.
-        if (PhoneUtils.hasPhoneProviderExtras(intent)) {
-            inCallUiState.setProviderInfo(intent);
-        } else {
-            inCallUiState.clearProviderInfo();
-        }
-
         CallStatusCode status = placeCallInternal(intent);
 
         switch (status) {
@@ -477,6 +473,9 @@
         // phone number to use for the outgoing call.
         Uri contactUri = intent.getData();
 
+        // If a gateway is used, extract the data here and pass that into placeCall.
+        final RawGatewayInfo rawGatewayInfo = mCallGatewayManager.getRawGatewayInfo(intent, number);
+
         // Watch out: PhoneUtils.placeCall() returns one of the
         // CALL_STATUS_* constants, not a CallStatusCode enum value.
         int callStatus = PhoneUtils.placeCall(mApp,
@@ -484,7 +483,8 @@
                                               number,
                                               contactUri,
                                               (isEmergencyNumber || isEmergencyIntent),
-                                              inCallUiState.providerGatewayUri);
+                                              rawGatewayInfo,
+                                              mCallGatewayManager);
 
         switch (callStatus) {
             case PhoneUtils.CALL_STATUS_DIALED:
diff --git a/src/com/android/phone/CallGatewayManager.java b/src/com/android/phone/CallGatewayManager.java
new file mode 100644
index 0000000..6fe2444
--- /dev/null
+++ b/src/com/android/phone/CallGatewayManager.java
@@ -0,0 +1,209 @@
+/*
+ * Copyright (C) 2013 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.
+ */
+
+package com.android.phone;
+
+import android.content.Intent;
+import android.net.Uri;
+import android.telephony.PhoneNumberUtils;
+import android.text.TextUtils;
+import android.util.Log;
+
+import com.android.internal.telephony.Connection;
+import com.google.android.collect.Maps;
+
+import java.util.HashMap;
+
+/**
+ * This class manages gateway information for outgoing calls. When calls are made, they may contain
+ * gateway information for services which route phone calls through their own service/numbers.
+ * The data consists of a number to call and the package name of the service. This data is used in
+ * two ways:<br/>
+ * 1. Call the appropriate routing number<br/>
+ * 2. Display information about the routing to the user<br/>
+ *
+ * <p>When an outgoing call is finally placed in PhoneUtils.placeCall, it uses this class to get the
+ * proper number to dial. It also saves an association between the connection object and the gateway
+ * data into this class.  This association is later used in CallModeler when building Call objects
+ * to send to the UI which require the gateway data to show an alert to users.
+ */
+public class CallGatewayManager {
+    private static final String LOG_TAG = CallGatewayManager.class.getSimpleName();
+
+    /**
+     * Intent extra to specify the package name of the gateway
+     * provider.  Used to get the name displayed in the in-call screen
+     * during the call setup. The value is a string.
+     */
+    // TODO: This extra is currently set by the gateway application as
+    // a temporary measure. Ultimately, the framework will securely
+    // set it.
+    /* package */ static final String EXTRA_GATEWAY_PROVIDER_PACKAGE =
+            "com.android.phone.extra.GATEWAY_PROVIDER_PACKAGE";
+
+    /**
+     * Intent extra to specify the URI of the provider to place the
+     * call. The value is a string. It holds the gateway address
+     * (phone gateway URL should start with the 'tel:' scheme) that
+     * will actually be contacted to call the number passed in the
+     * intent URL or in the EXTRA_PHONE_NUMBER extra.
+     */
+    // TODO: Should the value be a Uri (Parcelable)? Need to make sure
+    // MMI code '#' don't get confused as URI fragments.
+    /* package */ static final String EXTRA_GATEWAY_URI =
+            "com.android.phone.extra.GATEWAY_URI";
+
+    public static final RawGatewayInfo EMPTY_INFO = new RawGatewayInfo(null, null, null);
+
+    private final HashMap<Connection, RawGatewayInfo> mMap = Maps.newHashMap();
+
+    public CallGatewayManager() {
+    }
+
+    /**
+     * Static method returns an object containing the gateway data stored in the extras of the
+     * Intent parameter.  If no such data exists, returns a Null-Object RawGatewayInfo.
+     * @param intent The intent from which to read gateway data.
+     * @return A populated or empty RawGatewayInfo object.
+     */
+    public static RawGatewayInfo getRawGatewayInfo(Intent intent, String number) {
+        if (hasPhoneProviderExtras(intent)) {
+            return new RawGatewayInfo(intent.getStringExtra(EXTRA_GATEWAY_PROVIDER_PACKAGE),
+                    getProviderGatewayUri(intent), number);
+        }
+        return EMPTY_INFO;
+    }
+
+    /**
+     * This function sets the current mapping from connection to gatewayInfo so that CallModeler
+     * can request this data when creating Call objects.
+     * @param connection The connection object for the placed outgoing call.
+     * @param gatewayInfo Gateway info gathered using getRawGatewayInfo.
+     */
+    public void setGatewayInfoForConnection(Connection connection, RawGatewayInfo gatewayInfo) {
+        if (!gatewayInfo.isEmpty()) {
+            mMap.put(connection, gatewayInfo);
+        } else {
+            mMap.remove(connection);
+        }
+    }
+
+    /**
+     * Clears the gateway information previously stored via setGatewayInfoForConnection.
+     */
+    public void clearGatewayData(Connection connection) {
+        setGatewayInfoForConnection(connection, EMPTY_INFO);
+    }
+
+    /**
+     * If the parameter matches the connection object we previously saved through
+     * setGatewayInfoForConnection, return the associated raw gateway info data. If not, then
+     * return an empty raw gateway info.
+     */
+    public RawGatewayInfo getGatewayInfo(Connection connection) {
+        final RawGatewayInfo info = mMap.get(connection);
+        if (info != null) {
+            return info;
+        }
+
+        return EMPTY_INFO;
+    }
+
+    /**
+     * Check if all the provider's info is present in the intent.
+     * @param intent Expected to have the provider's extra.
+     * @return true if the intent has all the extras to build the
+     * in-call screen's provider info overlay.
+     */
+    public static boolean hasPhoneProviderExtras(Intent intent) {
+        if (null == intent) {
+            return false;
+        }
+        final String name = intent.getStringExtra(EXTRA_GATEWAY_PROVIDER_PACKAGE);
+        final String gatewayUri = intent.getStringExtra(EXTRA_GATEWAY_URI);
+
+        return !TextUtils.isEmpty(name) && !TextUtils.isEmpty(gatewayUri);
+    }
+
+    /**
+     * Copy all the expected extras set when a 3rd party provider is
+     * used from the source intent to the destination one.  Checks all
+     * the required extras are present, if any is missing, none will
+     * be copied.
+     * @param src Intent which may contain the provider's extras.
+     * @param dst Intent where a copy of the extras will be added if applicable.
+     */
+    public static void checkAndCopyPhoneProviderExtras(Intent src, Intent dst) {
+        if (!hasPhoneProviderExtras(src)) {
+            Log.d(LOG_TAG, "checkAndCopyPhoneProviderExtras: some or all extras are missing.");
+            return;
+        }
+
+        dst.putExtra(EXTRA_GATEWAY_PROVIDER_PACKAGE,
+                     src.getStringExtra(EXTRA_GATEWAY_PROVIDER_PACKAGE));
+        dst.putExtra(EXTRA_GATEWAY_URI,
+                     src.getStringExtra(EXTRA_GATEWAY_URI));
+    }
+
+    /**
+     * Return the gateway uri from the intent.
+     * @param intent With the gateway uri extra.
+     * @return The gateway URI or null if not found.
+     */
+    public static Uri getProviderGatewayUri(Intent intent) {
+        final String uri = intent.getStringExtra(EXTRA_GATEWAY_URI);
+        return TextUtils.isEmpty(uri) ? null : Uri.parse(uri);
+    }
+
+    /**
+     * Return a formatted version of the uri's scheme specific
+     * part. E.g for 'tel:12345678', return '1-234-5678'.
+     * @param uri A 'tel:' URI with the gateway phone number.
+     * @return the provider's address (from the gateway uri) formatted
+     * for user display. null if uri was null or its scheme was not 'tel:'.
+     */
+    public static String formatProviderUri(Uri uri) {
+        if (uri != null) {
+            if (Constants.SCHEME_TEL.equals(uri.getScheme())) {
+                return PhoneNumberUtils.formatNumber(uri.getSchemeSpecificPart());
+            } else {
+                return uri.toString();
+            }
+        }
+        return null;
+    }
+
+    public static class RawGatewayInfo {
+        public String packageName;
+        public Uri gatewayUri;
+        public String trueNumber;
+
+        public RawGatewayInfo(String packageName, Uri gatewayUri,
+                String trueNumber) {
+            this.packageName = packageName;
+            this.gatewayUri = gatewayUri;
+            this.trueNumber = trueNumber;
+        }
+
+        public String getFormattedGatewayNumber() {
+            return formatProviderUri(gatewayUri);
+        }
+
+        public boolean isEmpty() {
+            return TextUtils.isEmpty(packageName) || gatewayUri == null;
+        }
+    }
+}
diff --git a/src/com/android/phone/CallModeler.java b/src/com/android/phone/CallModeler.java
index 89dcb21..a5e2044 100644
--- a/src/com/android/phone/CallModeler.java
+++ b/src/com/android/phone/CallModeler.java
@@ -35,6 +35,7 @@
 import com.android.internal.telephony.Phone;
 import com.android.internal.telephony.PhoneConstants;
 import com.android.internal.telephony.TelephonyCapabilities;
+import com.android.phone.CallGatewayManager.RawGatewayInfo;
 import com.android.services.telephony.common.Call;
 import com.android.services.telephony.common.Call.Capabilities;
 import com.android.services.telephony.common.Call.State;
@@ -84,6 +85,7 @@
 
     private final CallStateMonitor mCallStateMonitor;
     private final CallManager mCallManager;
+    private final CallGatewayManager mCallGatewayManager;
     private final HashMap<Connection, Call> mCallMap = Maps.newHashMap();
     private final HashMap<Connection, Call> mConfCallMap = Maps.newHashMap();
     private final AtomicInteger mNextCallId = new AtomicInteger(CALL_ID_START_VALUE);
@@ -91,10 +93,12 @@
     private RejectWithTextMessageManager mRejectWithTextMessageManager;
 
     public CallModeler(CallStateMonitor callStateMonitor, CallManager callManager,
-            RejectWithTextMessageManager rejectWithTextMessageManager) {
+            RejectWithTextMessageManager rejectWithTextMessageManager,
+            CallGatewayManager callGatewayManager) {
         mCallStateMonitor = callStateMonitor;
         mCallManager = callManager;
         mRejectWithTextMessageManager = rejectWithTextMessageManager;
+        mCallGatewayManager = callGatewayManager;
 
         mCallStateMonitor.addListener(this);
     }
@@ -330,6 +334,29 @@
     }
 
     /**
+     * Sets the new call state onto the call and performs some additional logic
+     * associated with setting the state.
+     */
+    private void setNewState(Call call, int newState, Connection connection) {
+        Preconditions.checkState(call.getState() != newState);
+
+        // When starting an outgoing call, we need to grab gateway information
+        // for the call, if available, and set it.
+        final RawGatewayInfo info = mCallGatewayManager.getGatewayInfo(connection);
+
+        if (newState == Call.State.DIALING) {
+            if (!info.isEmpty()) {
+                call.setGatewayNumber(info.getFormattedGatewayNumber());
+                call.setGatewayPackage(info.packageName);
+            }
+        } else if (!Call.State.isConnected(newState)) {
+            mCallGatewayManager.clearGatewayData(connection);
+        }
+
+        call.setState(newState);
+    }
+
+    /**
      * Updates the Call properties to match the state of the connection object
      * that it represents.
      * @param call The call object to update.
@@ -344,7 +371,7 @@
         final int newState = translateStateFromTelephony(connection, isForConference);
 
         if (call.getState() != newState) {
-            call.setState(newState);
+            setNewState(call, newState, connection);
             changed = true;
         }
 
@@ -362,29 +389,38 @@
         }
 
         if (!isForConference) {
+            // Number
             final String oldNumber = call.getNumber();
-            if (TextUtils.isEmpty(oldNumber) || !oldNumber.equals(connection.getAddress())) {
-                call.setNumber(connection.getAddress());
+            String newNumber = connection.getAddress();
+            RawGatewayInfo info = mCallGatewayManager.getGatewayInfo(connection);
+            if (!info.isEmpty()) {
+                newNumber = info.trueNumber;
+            }
+            if (TextUtils.isEmpty(oldNumber) || !oldNumber.equals(newNumber)) {
+                call.setNumber(newNumber);
                 changed = true;
             }
 
+            // Number presentation
             final int newNumberPresentation = connection.getNumberPresentation();
             if (call.getNumberPresentation() != newNumberPresentation) {
                 call.setNumberPresentation(newNumberPresentation);
                 changed = true;
             }
 
-            final int newCnapNamePresentation = connection.getCnapNamePresentation();
-            if (call.getCnapNamePresentation() != newCnapNamePresentation) {
-                call.setCnapNamePresentation(newCnapNamePresentation);
-                changed = true;
-            }
-
+            // Name
             final String oldCnapName = call.getCnapName();
             if (TextUtils.isEmpty(oldCnapName) || !oldCnapName.equals(connection.getCnapName())) {
                 call.setCnapName(connection.getCnapName());
                 changed = true;
             }
+
+            // Name Presentation
+            final int newCnapNamePresentation = connection.getCnapNamePresentation();
+            if (call.getCnapNamePresentation() != newCnapNamePresentation) {
+                call.setCnapNamePresentation(newCnapNamePresentation);
+                changed = true;
+            }
         } else {
 
             // update the list of children by:
diff --git a/src/com/android/phone/CallNotifier.java b/src/com/android/phone/CallNotifier.java
index 31b0c66..de5052f 100644
--- a/src/com/android/phone/CallNotifier.java
+++ b/src/com/android/phone/CallNotifier.java
@@ -1165,7 +1165,7 @@
                     if (autoretrySetting == InCallScreen.AUTO_RETRY_ON) {
                         // TODO: (Moto): The contact reference data may need to be stored and use
                         // here when redialing a call. For now, pass in NULL as the URI parameter.
-                        PhoneUtils.placeCall(mApplication, phone, number, null, false, null);
+                        PhoneUtils.placeCall(mApplication, phone, number, null, false);
                         mIsCdmaRedialCall = true;
                     } else {
                         mIsCdmaRedialCall = false;
diff --git a/src/com/android/phone/EmergencyCallHelper.java b/src/com/android/phone/EmergencyCallHelper.java
index 7f5b0d2..a23e3e0 100644
--- a/src/com/android/phone/EmergencyCallHelper.java
+++ b/src/com/android/phone/EmergencyCallHelper.java
@@ -392,8 +392,7 @@
                                               mPhone,
                                               mNumber,
                                               null,  // contactUri
-                                              true,  // isEmergencyCall
-                                              null);  // gatewayUri
+                                              true); // isEmergencyCall
         if (DBG) log("- PhoneUtils.placeCall() returned status = " + callStatus);
 
         boolean success;
diff --git a/src/com/android/phone/InCallScreen.java b/src/com/android/phone/InCallScreen.java
index 31f680b..57006bb 100644
--- a/src/com/android/phone/InCallScreen.java
+++ b/src/com/android/phone/InCallScreen.java
@@ -97,29 +97,6 @@
     // TODO: Should be EXTRA_SHOW_DIALPAD for consistency.
     static final String SHOW_DIALPAD_EXTRA = "com.android.phone.ShowDialpad";
 
-    /**
-     * Intent extra to specify the package name of the gateway
-     * provider.  Used to get the name displayed in the in-call screen
-     * during the call setup. The value is a string.
-     */
-    // TODO: This extra is currently set by the gateway application as
-    // a temporary measure. Ultimately, the framework will securely
-    // set it.
-    /* package */ static final String EXTRA_GATEWAY_PROVIDER_PACKAGE =
-            "com.android.phone.extra.GATEWAY_PROVIDER_PACKAGE";
-
-    /**
-     * Intent extra to specify the URI of the provider to place the
-     * call. The value is a string. It holds the gateway address
-     * (phone gateway URL should start with the 'tel:' scheme) that
-     * will actually be contacted to call the number passed in the
-     * intent URL or in the EXTRA_PHONE_NUMBER extra.
-     */
-    // TODO: Should the value be a Uri (Parcelable)? Need to make sure
-    // MMI code '#' don't get confused as URI fragments.
-    /* package */ static final String EXTRA_GATEWAY_URI =
-            "com.android.phone.extra.GATEWAY_URI";
-
     // Amount of time (in msec) that we display the "Call ended" state.
     // The "short" value is for calls ended by the local user, and the
     // "long" value is for calls ended by the remote caller.
@@ -371,7 +348,6 @@
                     break;
 
                 case EVENT_HIDE_PROVIDER_INFO:
-                    mApp.inCallUiState.providerInfoVisible = false;
                     if (mCallCard != null) {
                         mCallCard.updateState(mCM);
                     }
@@ -731,11 +707,6 @@
 
         mIsForegroundActivity = false;
 
-        // Force a clear of the provider info frame. Since the
-        // frame is removed using a timed message, it is
-        // possible we missed it if the prev call was interrupted.
-        mApp.inCallUiState.providerInfoVisible = false;
-
         // "show-already-disconnected-state" should be effective just during the first wake-up.
         // We should never allow it to stay true after that.
         mApp.inCallUiState.showAlreadyDisconnectedState = false;
diff --git a/src/com/android/phone/InCallUiState.java b/src/com/android/phone/InCallUiState.java
index 3b700d7..126ef63 100644
--- a/src/com/android/phone/InCallUiState.java
+++ b/src/com/android/phone/InCallUiState.java
@@ -340,52 +340,6 @@
         return (progressIndication != ProgressIndicationType.NONE);
     }
 
-
-    //
-    // (4) Optional info when a 3rd party "provider" is used.
-    //     @see InCallScreen#requestRemoveProviderInfoWithDelay()
-    //     @see CallCard#updateCallStateWidgets()
-    //
-
-    // TODO: maybe isolate all the provider-related stuff out to a
-    //       separate inner class?
-    boolean providerInfoVisible;
-    CharSequence providerLabel;
-    Drawable providerIcon;
-    Uri providerGatewayUri;
-    // The formatted address extracted from mProviderGatewayUri. User visible.
-    String providerAddress;
-
-    /**
-     * Set the fields related to the provider support
-     * based on the specified intent.
-     */
-    public void setProviderInfo(Intent intent) {
-        providerLabel = PhoneUtils.getProviderLabel(mContext, intent);
-        providerIcon = PhoneUtils.getProviderIcon(mContext, intent);
-        providerGatewayUri = PhoneUtils.getProviderGatewayUri(intent);
-        providerAddress = PhoneUtils.formatProviderUri(providerGatewayUri);
-        providerInfoVisible = true;
-
-        // ...but if any of the "required" fields are missing, completely
-        // disable the overlay.
-        if (TextUtils.isEmpty(providerLabel) || providerIcon == null ||
-            providerGatewayUri == null || TextUtils.isEmpty(providerAddress)) {
-            clearProviderInfo();
-        }
-    }
-
-    /**
-     * Clear all the fields related to the provider support.
-     */
-    public void clearProviderInfo() {
-        providerInfoVisible = false;
-        providerLabel = null;
-        providerIcon = null;
-        providerGatewayUri = null;
-        providerAddress = null;
-    }
-
     /**
      * "Call origin" of the most recent phone call.
      *
@@ -435,15 +389,6 @@
             log("  - pending call status code: none");
         }
         log("  - progressIndication: " + progressIndication);
-        if (providerInfoVisible) {
-            log("  - provider info VISIBLE: "
-                  + providerLabel + " / "
-                  + providerIcon  + " / "
-                  + providerGatewayUri + " / "
-                  + providerAddress);
-        } else {
-            log("  - provider info: none");
-        }
         log("  - latestActiveCallOrigin: " + latestActiveCallOrigin);
     }
 
diff --git a/src/com/android/phone/OtaUtils.java b/src/com/android/phone/OtaUtils.java
index a59c2e6..e713df9 100644
--- a/src/com/android/phone/OtaUtils.java
+++ b/src/com/android/phone/OtaUtils.java
@@ -459,9 +459,8 @@
         int callStatus = PhoneUtils.placeCall(context,
                                               phone,
                                               number,
-                                              null,  // contactRef
-                                              false,  //isEmergencyCall
-                                              null);  // gatewayUri
+                                              null,   // contactRef
+                                              false); //isEmergencyCall
 
         if (callStatus == PhoneUtils.CALL_STATUS_DIALED) {
             if (DBG) log("  ==> successful return from placeCall(): callStatus = " + callStatus);
diff --git a/src/com/android/phone/OutgoingCallBroadcaster.java b/src/com/android/phone/OutgoingCallBroadcaster.java
index b9aea52..c5e8953 100644
--- a/src/com/android/phone/OutgoingCallBroadcaster.java
+++ b/src/com/android/phone/OutgoingCallBroadcaster.java
@@ -300,7 +300,7 @@
 
         Intent newIntent = new Intent(Intent.ACTION_CALL, uri);
         newIntent.putExtra(EXTRA_ACTUAL_NUMBER_TO_DIAL, number);
-        PhoneUtils.checkAndCopyPhoneProviderExtras(intent, newIntent);
+        CallGatewayManager.checkAndCopyPhoneProviderExtras(intent, newIntent);
 
         // Finally, launch the SipCallOptionHandler, with the copy of the
         // original CALL intent stashed away in the EXTRA_NEW_CALL_INTENT
@@ -638,7 +638,7 @@
         if (number != null) {
             broadcastIntent.putExtra(Intent.EXTRA_PHONE_NUMBER, number);
         }
-        PhoneUtils.checkAndCopyPhoneProviderExtras(intent, broadcastIntent);
+        CallGatewayManager.checkAndCopyPhoneProviderExtras(intent, broadcastIntent);
         broadcastIntent.putExtra(EXTRA_ALREADY_CALLED, callNow);
         broadcastIntent.putExtra(EXTRA_ORIGINAL_URI, uri.toString());
         // Need to raise foreground in-call UI as soon as possible while allowing 3rd party app
diff --git a/src/com/android/phone/PhoneGlobals.java b/src/com/android/phone/PhoneGlobals.java
index 9ed0470..165ae67 100644
--- a/src/com/android/phone/PhoneGlobals.java
+++ b/src/com/android/phone/PhoneGlobals.java
@@ -171,6 +171,7 @@
     private AudioRouter audioRouter;
     private BluetoothManager bluetoothManager;
     private CallCommandService callCommandService;
+    private CallGatewayManager callGatewayManager;
     private CallHandlerServiceProxy callHandlerServiceProxy;
     private CallModeler callModeler;
     private CallStateMonitor callStateMonitor;
@@ -474,10 +475,13 @@
 
             CallLogger callLogger = new CallLogger(this, new CallLogAsync());
 
+            callGatewayManager = new CallGatewayManager();
+
             // Create the CallController singleton, which is the interface
             // to the telephony layer for user-initiated telephony functionality
             // (like making outgoing calls.)
-            callController = CallController.init(this, callLogger);
+            callController = CallController.init(this, callLogger, callGatewayManager);
+
             // ...and also the InCallUiState instance, used by the CallController to
             // keep track of some "persistent state" of the in-call UI.
             inCallUiState = InCallUiState.init(this);
@@ -495,7 +499,8 @@
             rejectWithTextMessageManager = new RejectWithTextMessageManager();
 
             // Creates call models for use with CallHandlerService.
-            callModeler = new CallModeler(callStateMonitor, mCM, rejectWithTextMessageManager);
+            callModeler = new CallModeler(callStateMonitor, mCM, rejectWithTextMessageManager,
+                    callGatewayManager);
 
             // Plays DTMF Tones
             dtmfTonePlayer = new DTMFTonePlayer(mCM, callModeler);
diff --git a/src/com/android/phone/PhoneUtils.java b/src/com/android/phone/PhoneUtils.java
index 9671c17..6b96737 100644
--- a/src/com/android/phone/PhoneUtils.java
+++ b/src/com/android/phone/PhoneUtils.java
@@ -59,6 +59,7 @@
 import com.android.internal.telephony.TelephonyProperties;
 import com.android.internal.telephony.cdma.CdmaConnection;
 import com.android.internal.telephony.sip.SipPhone;
+import com.android.phone.CallGatewayManager.RawGatewayInfo;
 
 import java.util.ArrayList;
 import java.util.Arrays;
@@ -561,6 +562,15 @@
     }
 
     /**
+     * @see placeCall below
+     */
+    public static int placeCall(Context context, Phone phone, String number, Uri contactRef,
+            boolean isEmergencyCall) {
+        return placeCall(context, phone, number, contactRef, isEmergencyCall,
+                CallGatewayManager.EMPTY_INFO, null);
+    }
+
+    /**
      * Dial the number using the phone passed in.
      *
      * If the connection is establised, this method issues a sync call
@@ -578,12 +588,14 @@
      * emergency call
      * @param gatewayUri Is the address used to setup the connection, null
      * if not using a gateway
+     * @param callGateway Class for setting gateway data on a successful call.
      *
      * @return either CALL_STATUS_DIALED or CALL_STATUS_FAILED
      */
-    public static int placeCall(Context context, Phone phone,
-            String number, Uri contactRef, boolean isEmergencyCall,
-            Uri gatewayUri) {
+    public static int placeCall(Context context, Phone phone, String number, Uri contactRef,
+            boolean isEmergencyCall, RawGatewayInfo gatewayInfo, CallGatewayManager callGateway) {
+        final Uri gatewayUri = gatewayInfo.gatewayUri;
+
         if (VDBG) {
             log("placeCall()... number: '" + number + "'"
                     + ", GW:'" + gatewayUri + "'"
@@ -642,6 +654,11 @@
             // we dialed an MMI (see below).
         }
 
+        // Now that the call is successful, we can save the gateway info for the call
+        if (callGateway != null) {
+            callGateway.setGatewayInfoForConnection(connection, gatewayInfo);
+        }
+
         int phoneType = phone.getPhoneType();
 
         // On GSM phones, null is returned for MMI codes
@@ -2321,107 +2338,6 @@
     //
 
     /**
-     * Check if all the provider's info is present in the intent.
-     * @param intent Expected to have the provider's extra.
-     * @return true if the intent has all the extras to build the
-     * in-call screen's provider info overlay.
-     */
-    /* package */ static boolean hasPhoneProviderExtras(Intent intent) {
-        if (null == intent) {
-            return false;
-        }
-        final String name = intent.getStringExtra(InCallScreen.EXTRA_GATEWAY_PROVIDER_PACKAGE);
-        final String gatewayUri = intent.getStringExtra(InCallScreen.EXTRA_GATEWAY_URI);
-
-        return !TextUtils.isEmpty(name) && !TextUtils.isEmpty(gatewayUri);
-    }
-
-    /**
-     * Copy all the expected extras set when a 3rd party provider is
-     * used from the source intent to the destination one.  Checks all
-     * the required extras are present, if any is missing, none will
-     * be copied.
-     * @param src Intent which may contain the provider's extras.
-     * @param dst Intent where a copy of the extras will be added if applicable.
-     */
-    /* package */ static void checkAndCopyPhoneProviderExtras(Intent src, Intent dst) {
-        if (!hasPhoneProviderExtras(src)) {
-            Log.d(LOG_TAG, "checkAndCopyPhoneProviderExtras: some or all extras are missing.");
-            return;
-        }
-
-        dst.putExtra(InCallScreen.EXTRA_GATEWAY_PROVIDER_PACKAGE,
-                     src.getStringExtra(InCallScreen.EXTRA_GATEWAY_PROVIDER_PACKAGE));
-        dst.putExtra(InCallScreen.EXTRA_GATEWAY_URI,
-                     src.getStringExtra(InCallScreen.EXTRA_GATEWAY_URI));
-    }
-
-    /**
-     * Get the provider's label from the intent.
-     * @param context to lookup the provider's package name.
-     * @param intent with an extra set to the provider's package name.
-     * @return The provider's application label. null if an error
-     * occurred during the lookup of the package name or the label.
-     */
-    /* package */ static CharSequence getProviderLabel(Context context, Intent intent) {
-        String packageName = intent.getStringExtra(InCallScreen.EXTRA_GATEWAY_PROVIDER_PACKAGE);
-        PackageManager pm = context.getPackageManager();
-
-        try {
-            ApplicationInfo info = pm.getApplicationInfo(packageName, 0);
-
-            return pm.getApplicationLabel(info);
-        } catch (PackageManager.NameNotFoundException e) {
-            return null;
-        }
-    }
-
-    /**
-     * Get the provider's icon.
-     * @param context to lookup the provider's icon.
-     * @param intent with an extra set to the provider's package name.
-     * @return The provider's application icon. null if an error occured during the icon lookup.
-     */
-    /* package */ static Drawable getProviderIcon(Context context, Intent intent) {
-        String packageName = intent.getStringExtra(InCallScreen.EXTRA_GATEWAY_PROVIDER_PACKAGE);
-        PackageManager pm = context.getPackageManager();
-
-        try {
-            return pm.getApplicationIcon(packageName);
-        } catch (PackageManager.NameNotFoundException e) {
-            return null;
-        }
-    }
-
-    /**
-     * Return the gateway uri from the intent.
-     * @param intent With the gateway uri extra.
-     * @return The gateway URI or null if not found.
-     */
-    /* package */ static Uri getProviderGatewayUri(Intent intent) {
-        String uri = intent.getStringExtra(InCallScreen.EXTRA_GATEWAY_URI);
-        return TextUtils.isEmpty(uri) ? null : Uri.parse(uri);
-    }
-
-    /**
-     * Return a formatted version of the uri's scheme specific
-     * part. E.g for 'tel:12345678', return '1-234-5678'.
-     * @param uri A 'tel:' URI with the gateway phone number.
-     * @return the provider's address (from the gateway uri) formatted
-     * for user display. null if uri was null or its scheme was not 'tel:'.
-     */
-    /* package */ static String formatProviderUri(Uri uri) {
-        if (null != uri) {
-            if (Constants.SCHEME_TEL.equals(uri.getScheme())) {
-                return PhoneNumberUtils.formatNumber(uri.getSchemeSpecificPart());
-            } else {
-                return uri.toString();
-            }
-        }
-        return null;
-    }
-
-    /**
      * Check if a phone number can be route through a 3rd party
      * gateway. The number must be a global phone number in numerical
      * form (1-800-666-SEXY won't work).
@@ -2432,7 +2348,7 @@
      * @param number To be dialed via a 3rd party gateway.
      * @return true If the number can be routed through the 3rd party network.
      */
-    /* package */ static boolean isRoutableViaGateway(String number) {
+    private static boolean isRoutableViaGateway(String number) {
         if (TextUtils.isEmpty(number)) {
             return false;
         }
diff --git a/src/com/android/phone/SipCallOptionHandler.java b/src/com/android/phone/SipCallOptionHandler.java
index 500f322..295e886 100644
--- a/src/com/android/phone/SipCallOptionHandler.java
+++ b/src/com/android/phone/SipCallOptionHandler.java
@@ -176,7 +176,7 @@
         // call via the default pstn network. However, if one just alters
         // the destination directly, then we still let it go through the
         // Internet call option process.
-        if (!PhoneUtils.hasPhoneProviderExtras(mIntent)) {
+        if (!CallGatewayManager.hasPhoneProviderExtras(mIntent)) {
             if (!isNetworkConnected()) {
                 if (!isRegularCall) {
                     showDialog(DIALOG_NO_INTERNET_ERROR);