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.telecom.PhoneAccount;
     22 import android.telephony.PhoneNumberUtils;
     23 import android.text.TextUtils;
     24 import android.util.Log;
     25 
     26 import com.android.internal.telephony.Connection;
     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.
     41  */
     42 public class CallGatewayManager {
     43     private static final String LOG_TAG = CallGatewayManager.class.getSimpleName();
     44 
     45     /**
     46      * Intent extra to specify the package name of the gateway
     47      * provider.  Used to get the name displayed in the in-call screen
     48      * during the call setup. The value is a string.
     49      */
     50     // TODO: This extra is currently set by the gateway application as
     51     // a temporary measure. Ultimately, the framework will securely
     52     // set it.
     53     /* package */ static final String EXTRA_GATEWAY_PROVIDER_PACKAGE =
     54             "com.android.phone.extra.GATEWAY_PROVIDER_PACKAGE";
     55 
     56     /**
     57      * Intent extra to specify the URI of the provider to place the
     58      * call. The value is a string. It holds the gateway address
     59      * (phone gateway URL should start with the 'tel:' scheme) that
     60      * will actually be contacted to call the number passed in the
     61      * intent URL or in the EXTRA_PHONE_NUMBER extra.
     62      */
     63     // TODO: Should the value be a Uri (Parcelable)? Need to make sure
     64     // MMI code '#' don't get confused as URI fragments.
     65     /* package */ static final String EXTRA_GATEWAY_URI =
     66             "com.android.phone.extra.GATEWAY_URI";
     67 
     68     public static final RawGatewayInfo EMPTY_INFO = new RawGatewayInfo(null, null, null);
     69 
     70     private final ConcurrentHashMap<Connection, RawGatewayInfo> mMap =
     71         new ConcurrentHashMap<Connection, RawGatewayInfo>(4, 0.9f, 1);
     72 
     73     private static CallGatewayManager sSingleton;
     74 
     75     public static synchronized CallGatewayManager getInstance() {
     76         if (sSingleton == null) {
     77             sSingleton = new CallGatewayManager();
     78         }
     79         return sSingleton;
     80     }
     81 
     82     private CallGatewayManager() {
     83     }
     84 
     85     /**
     86      * Static method returns an object containing the gateway data stored in the extras of the
     87      * Intent parameter.  If no such data exists, returns a Null-Object RawGatewayInfo.
     88      * @param intent The intent from which to read gateway data.
     89      * @return A populated or empty RawGatewayInfo object.
     90      */
     91     public static RawGatewayInfo getRawGatewayInfo(Intent intent, String number) {
     92         if (hasPhoneProviderExtras(intent)) {
     93             return new RawGatewayInfo(intent.getStringExtra(EXTRA_GATEWAY_PROVIDER_PACKAGE),
     94                     getProviderGatewayUri(intent), number);
     95         }
     96         return EMPTY_INFO;
     97     }
     98 
     99     /**
    100      * This function sets the current mapping from connection to gatewayInfo.
    101      * @param connection The connection object for the placed outgoing call.
    102      * @param gatewayInfo Gateway info gathered using getRawGatewayInfo.
    103      */
    104     public void setGatewayInfoForConnection(Connection connection, RawGatewayInfo gatewayInfo) {
    105         if (!gatewayInfo.isEmpty()) {
    106             mMap.put(connection, gatewayInfo);
    107         } else {
    108             mMap.remove(connection);
    109         }
    110     }
    111 
    112     /**
    113      * Clears the gateway information previously stored via setGatewayInfoForConnection.
    114      */
    115     public void clearGatewayData(Connection connection) {
    116         setGatewayInfoForConnection(connection, EMPTY_INFO);
    117     }
    118 
    119     /**
    120      * If the parameter matches the connection object we previously saved through
    121      * setGatewayInfoForConnection, return the associated raw gateway info data. If not, then
    122      * return an empty raw gateway info.
    123      */
    124     public RawGatewayInfo getGatewayInfo(Connection connection) {
    125         final RawGatewayInfo info = mMap.get(connection);
    126         if (info != null) {
    127             return info;
    128         }
    129 
    130         return EMPTY_INFO;
    131     }
    132 
    133     /**
    134      * Check if all the provider's info is present in the intent.
    135      * @param intent Expected to have the provider's extra.
    136      * @return true if the intent has all the extras to build the
    137      * in-call screen's provider info overlay.
    138      */
    139     public static boolean hasPhoneProviderExtras(Intent intent) {
    140         if (null == intent) {
    141             return false;
    142         }
    143         final String name = intent.getStringExtra(EXTRA_GATEWAY_PROVIDER_PACKAGE);
    144         final String gatewayUri = intent.getStringExtra(EXTRA_GATEWAY_URI);
    145 
    146         return !TextUtils.isEmpty(name) && !TextUtils.isEmpty(gatewayUri);
    147     }
    148 
    149     /**
    150      * Copy all the expected extras set when a 3rd party provider is
    151      * used from the source intent to the destination one.  Checks all
    152      * the required extras are present, if any is missing, none will
    153      * be copied.
    154      * @param src Intent which may contain the provider's extras.
    155      * @param dst Intent where a copy of the extras will be added if applicable.
    156      */
    157     public static void checkAndCopyPhoneProviderExtras(Intent src, Intent dst) {
    158         if (!hasPhoneProviderExtras(src)) {
    159             Log.d(LOG_TAG, "checkAndCopyPhoneProviderExtras: some or all extras are missing.");
    160             return;
    161         }
    162 
    163         dst.putExtra(EXTRA_GATEWAY_PROVIDER_PACKAGE,
    164                      src.getStringExtra(EXTRA_GATEWAY_PROVIDER_PACKAGE));
    165         dst.putExtra(EXTRA_GATEWAY_URI,
    166                      src.getStringExtra(EXTRA_GATEWAY_URI));
    167     }
    168 
    169     /**
    170      * Return the gateway uri from the intent.
    171      * @param intent With the gateway uri extra.
    172      * @return The gateway URI or null if not found.
    173      */
    174     public static Uri getProviderGatewayUri(Intent intent) {
    175         final String uri = intent.getStringExtra(EXTRA_GATEWAY_URI);
    176         return TextUtils.isEmpty(uri) ? null : Uri.parse(uri);
    177     }
    178 
    179     /**
    180      * Return a formatted version of the uri's scheme specific
    181      * part. E.g for 'tel:12345678', return '1-234-5678'.
    182      * @param uri A 'tel:' URI with the gateway phone number.
    183      * @return the provider's address (from the gateway uri) formatted
    184      * for user display. null if uri was null or its scheme was not 'tel:'.
    185      */
    186     public static String formatProviderUri(Uri uri) {
    187         if (uri != null) {
    188             if (PhoneAccount.SCHEME_TEL.equals(uri.getScheme())) {
    189                 return PhoneNumberUtils.formatNumber(uri.getSchemeSpecificPart());
    190             } else {
    191                 return uri.toString();
    192             }
    193         }
    194         return null;
    195     }
    196 
    197     public static class RawGatewayInfo {
    198         public String packageName;
    199         public Uri gatewayUri;
    200         public String trueNumber;
    201 
    202         public RawGatewayInfo(String packageName, Uri gatewayUri,
    203                 String trueNumber) {
    204             this.packageName = packageName;
    205             this.gatewayUri = gatewayUri;
    206             this.trueNumber = trueNumber;
    207         }
    208 
    209         public String getFormattedGatewayNumber() {
    210             return formatProviderUri(gatewayUri);
    211         }
    212 
    213         public boolean isEmpty() {
    214             return TextUtils.isEmpty(packageName) || gatewayUri == null;
    215         }
    216     }
    217 }
    218