Home | History | Annotate | Download | only in phone
      1 /*
      2  * Copyright (C) 2013 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 package com.android.phone;
     18 
     19 import android.content.Intent;
     20 import android.net.Uri;
     21 import android.telephony.PhoneNumberUtils;
     22 import android.text.TextUtils;
     23 import android.util.Log;
     24 
     25 import com.android.internal.telephony.Connection;
     26 import com.google.android.collect.Maps;
     27 
     28 import java.util.concurrent.ConcurrentHashMap;
     29 
     30 /**
     31  * This class manages gateway information for outgoing calls. When calls are made, they may contain
     32  * gateway information for services which route phone calls through their own service/numbers.
     33  * The data consists of a number to call and the package name of the service. This data is used in
     34  * two ways:<br/>
     35  * 1. Call the appropriate routing number<br/>
     36  * 2. Display information about the routing to the user<br/>
     37  *
     38  * <p>When an outgoing call is finally placed in PhoneUtils.placeCall, it uses this class to get the
     39  * proper number to dial. It also saves an association between the connection object and the gateway
     40  * data into this class.  This association is later used in CallModeler when building Call objects
     41  * to send to the UI which require the gateway data to show an alert to users.
     42  */
     43 public class CallGatewayManager {
     44     private static final String LOG_TAG = CallGatewayManager.class.getSimpleName();
     45 
     46     /**
     47      * Intent extra to specify the package name of the gateway
     48      * provider.  Used to get the name displayed in the in-call screen
     49      * during the call setup. The value is a string.
     50      */
     51     // TODO: This extra is currently set by the gateway application as
     52     // a temporary measure. Ultimately, the framework will securely
     53     // set it.
     54     /* package */ static final String EXTRA_GATEWAY_PROVIDER_PACKAGE =
     55             "com.android.phone.extra.GATEWAY_PROVIDER_PACKAGE";
     56 
     57     /**
     58      * Intent extra to specify the URI of the provider to place the
     59      * call. The value is a string. It holds the gateway address
     60      * (phone gateway URL should start with the 'tel:' scheme) that
     61      * will actually be contacted to call the number passed in the
     62      * intent URL or in the EXTRA_PHONE_NUMBER extra.
     63      */
     64     // TODO: Should the value be a Uri (Parcelable)? Need to make sure
     65     // MMI code '#' don't get confused as URI fragments.
     66     /* package */ static final String EXTRA_GATEWAY_URI =
     67             "com.android.phone.extra.GATEWAY_URI";
     68 
     69     public static final RawGatewayInfo EMPTY_INFO = new RawGatewayInfo(null, null, null);
     70 
     71     private final ConcurrentHashMap<Connection, RawGatewayInfo> mMap =
     72         new ConcurrentHashMap<Connection, RawGatewayInfo>(4, 0.9f, 1);
     73 
     74     private static CallGatewayManager sSingleton;
     75 
     76     public static synchronized CallGatewayManager getInstance() {
     77         if (sSingleton == null) {
     78             sSingleton = new CallGatewayManager();
     79         }
     80         return sSingleton;
     81     }
     82 
     83     private CallGatewayManager() {
     84     }
     85 
     86     /**
     87      * Static method returns an object containing the gateway data stored in the extras of the
     88      * Intent parameter.  If no such data exists, returns a Null-Object RawGatewayInfo.
     89      * @param intent The intent from which to read gateway data.
     90      * @return A populated or empty RawGatewayInfo object.
     91      */
     92     public static RawGatewayInfo getRawGatewayInfo(Intent intent, String number) {
     93         if (hasPhoneProviderExtras(intent)) {
     94             return new RawGatewayInfo(intent.getStringExtra(EXTRA_GATEWAY_PROVIDER_PACKAGE),
     95                     getProviderGatewayUri(intent), number);
     96         }
     97         return EMPTY_INFO;
     98     }
     99 
    100     /**
    101      * This function sets the current mapping from connection to gatewayInfo so that CallModeler
    102      * can request this data when creating Call objects.
    103      * @param connection The connection object for the placed outgoing call.
    104      * @param gatewayInfo Gateway info gathered using getRawGatewayInfo.
    105      */
    106     public void setGatewayInfoForConnection(Connection connection, RawGatewayInfo gatewayInfo) {
    107         if (!gatewayInfo.isEmpty()) {
    108             mMap.put(connection, gatewayInfo);
    109         } else {
    110             mMap.remove(connection);
    111         }
    112     }
    113 
    114     /**
    115      * Clears the gateway information previously stored via setGatewayInfoForConnection.
    116      */
    117     public void clearGatewayData(Connection connection) {
    118         setGatewayInfoForConnection(connection, EMPTY_INFO);
    119     }
    120 
    121     /**
    122      * If the parameter matches the connection object we previously saved through
    123      * setGatewayInfoForConnection, return the associated raw gateway info data. If not, then
    124      * return an empty raw gateway info.
    125      */
    126     public RawGatewayInfo getGatewayInfo(Connection connection) {
    127         final RawGatewayInfo info = mMap.get(connection);
    128         if (info != null) {
    129             return info;
    130         }
    131 
    132         return EMPTY_INFO;
    133     }
    134 
    135     /**
    136      * Check if all the provider's info is present in the intent.
    137      * @param intent Expected to have the provider's extra.
    138      * @return true if the intent has all the extras to build the
    139      * in-call screen's provider info overlay.
    140      */
    141     public static boolean hasPhoneProviderExtras(Intent intent) {
    142         if (null == intent) {
    143             return false;
    144         }
    145         final String name = intent.getStringExtra(EXTRA_GATEWAY_PROVIDER_PACKAGE);
    146         final String gatewayUri = intent.getStringExtra(EXTRA_GATEWAY_URI);
    147 
    148         return !TextUtils.isEmpty(name) && !TextUtils.isEmpty(gatewayUri);
    149     }
    150 
    151     /**
    152      * Copy all the expected extras set when a 3rd party provider is
    153      * used from the source intent to the destination one.  Checks all
    154      * the required extras are present, if any is missing, none will
    155      * be copied.
    156      * @param src Intent which may contain the provider's extras.
    157      * @param dst Intent where a copy of the extras will be added if applicable.
    158      */
    159     public static void checkAndCopyPhoneProviderExtras(Intent src, Intent dst) {
    160         if (!hasPhoneProviderExtras(src)) {
    161             Log.d(LOG_TAG, "checkAndCopyPhoneProviderExtras: some or all extras are missing.");
    162             return;
    163         }
    164 
    165         dst.putExtra(EXTRA_GATEWAY_PROVIDER_PACKAGE,
    166                      src.getStringExtra(EXTRA_GATEWAY_PROVIDER_PACKAGE));
    167         dst.putExtra(EXTRA_GATEWAY_URI,
    168                      src.getStringExtra(EXTRA_GATEWAY_URI));
    169     }
    170 
    171     /**
    172      * Return the gateway uri from the intent.
    173      * @param intent With the gateway uri extra.
    174      * @return The gateway URI or null if not found.
    175      */
    176     public static Uri getProviderGatewayUri(Intent intent) {
    177         final String uri = intent.getStringExtra(EXTRA_GATEWAY_URI);
    178         return TextUtils.isEmpty(uri) ? null : Uri.parse(uri);
    179     }
    180 
    181     /**
    182      * Return a formatted version of the uri's scheme specific
    183      * part. E.g for 'tel:12345678', return '1-234-5678'.
    184      * @param uri A 'tel:' URI with the gateway phone number.
    185      * @return the provider's address (from the gateway uri) formatted
    186      * for user display. null if uri was null or its scheme was not 'tel:'.
    187      */
    188     public static String formatProviderUri(Uri uri) {
    189         if (uri != null) {
    190             if (Constants.SCHEME_TEL.equals(uri.getScheme())) {
    191                 return PhoneNumberUtils.formatNumber(uri.getSchemeSpecificPart());
    192             } else {
    193                 return uri.toString();
    194             }
    195         }
    196         return null;
    197     }
    198 
    199     public static class RawGatewayInfo {
    200         public String packageName;
    201         public Uri gatewayUri;
    202         public String trueNumber;
    203 
    204         public RawGatewayInfo(String packageName, Uri gatewayUri,
    205                 String trueNumber) {
    206             this.packageName = packageName;
    207             this.gatewayUri = gatewayUri;
    208             this.trueNumber = trueNumber;
    209         }
    210 
    211         public String getFormattedGatewayNumber() {
    212             return formatProviderUri(gatewayUri);
    213         }
    214 
    215         public boolean isEmpty() {
    216             return TextUtils.isEmpty(packageName) || gatewayUri == null;
    217         }
    218     }
    219 }
    220