blob: bdac98354ebb89e6d5025d9e50b5a688ac4af837 [file] [log] [blame]
/*
* 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.telecom.PhoneAccount;
import android.telephony.PhoneNumberUtils;
import android.text.TextUtils;
import android.util.Log;
import com.android.internal.telephony.Connection;
import java.util.concurrent.ConcurrentHashMap;
/**
* 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.
*/
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 ConcurrentHashMap<Connection, RawGatewayInfo> mMap =
new ConcurrentHashMap<Connection, RawGatewayInfo>(4, 0.9f, 1);
private static CallGatewayManager sSingleton;
public static synchronized CallGatewayManager getInstance() {
if (sSingleton == null) {
sSingleton = new CallGatewayManager();
}
return sSingleton;
}
private 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.
* @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 (PhoneAccount.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;
}
}
}