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