Add telecomm registration support to SIP.
Changes in CL:
1. Add SipAccountRegistry to manage telecom registrations
2. Register all accounts on ACTION_SIP_SERVICE_UP
3. Register specific account on ACTION_SIP_ADD_PHONE
4. Unregister specific account on ACTION_SIP_REMOVE_PHONE
5. Set the unique SIP uri as the PhoneAccount ID
6. Read phone account handle for outgoing calls instead of showing
a proprietary SIP chooser dialog, which I removed (see
SipProfileChooser.java).
7. Moved some of the error condition codes and error dialogs from
SipProfileChooser to SipConnectionService.
8. Set Phone account handle as extra on the incoming-call intent
9. Remove build files for SIP directory since it is already built into
TeleService.apk
Bug: 16836473
Bug: 16042786
Change-Id: I62d740c13ce61f181db295b9415c96ceef909177
diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index b948958..66821ee 100644
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -486,8 +486,10 @@
</service>
<receiver android:name="com.android.services.telephony.sip.SipBroadcastReceiver">
<intent-filter>
- <action android:name="com.android.phone.SIP_INCOMING_CALL" />
<action android:name="android.net.sip.SIP_SERVICE_UP" />
+ <action android:name="com.android.phone.SIP_INCOMING_CALL" />
+ <action android:name="com.android.phone.SIP_ADD_PHONE" />
+ <action android:name="com.android.phone.SIP_REMOVE_PHONE" />
</intent-filter>
</receiver>
diff --git a/res/drawable-hdpi/ic_dialer_sip_black_24dp.png b/res/drawable-hdpi/ic_dialer_sip_black_24dp.png
new file mode 100644
index 0000000..37dabfc
--- /dev/null
+++ b/res/drawable-hdpi/ic_dialer_sip_black_24dp.png
Binary files differ
diff --git a/res/drawable-mdpi/ic_dialer_sip_black_24dp.png b/res/drawable-mdpi/ic_dialer_sip_black_24dp.png
new file mode 100644
index 0000000..51d5e13
--- /dev/null
+++ b/res/drawable-mdpi/ic_dialer_sip_black_24dp.png
Binary files differ
diff --git a/res/drawable-xhdpi/ic_dialer_sip_black_24dp.png b/res/drawable-xhdpi/ic_dialer_sip_black_24dp.png
new file mode 100644
index 0000000..619a79f
--- /dev/null
+++ b/res/drawable-xhdpi/ic_dialer_sip_black_24dp.png
Binary files differ
diff --git a/sip/Android.mk b/sip/Android.mk
deleted file mode 100644
index cefb86d..0000000
--- a/sip/Android.mk
+++ /dev/null
@@ -1,31 +0,0 @@
-# Copyright 2014, 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.
-
-LOCAL_PATH:= $(call my-dir)
-
-include $(CLEAR_VARS)
-
-LOCAL_MODULE_TAGS := optional
-
-LOCAL_SRC_FILES := $(call all-java-files-under, src)
-LOCAL_RESOURCE_DIR := $(addprefix $(LOCAL_PATH)/, res)
-
-LOCAL_JAVA_LIBRARIES := telephony-common voip-common
-
-LOCAL_PACKAGE_NAME := com.android.services.telephony.sip
-
-LOCAL_PROGUARD_FLAG_FILES := proguard.flags
-
-include $(BUILD_PACKAGE)
-include $(CLEAR_VARS)
diff --git a/sip/AndroidManifest.xml b/sip/AndroidManifest.xml
deleted file mode 100644
index 0249abd..0000000
--- a/sip/AndroidManifest.xml
+++ /dev/null
@@ -1,22 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- ~ Copyright (C) 2014 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
- -->
-
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="com.android.services.telephony.sip">
-
-</manifest>
-
diff --git a/sip/src/com/android/services/telephony/sip/SipAccountRegistry.java b/sip/src/com/android/services/telephony/sip/SipAccountRegistry.java
new file mode 100644
index 0000000..8aca613
--- /dev/null
+++ b/sip/src/com/android/services/telephony/sip/SipAccountRegistry.java
@@ -0,0 +1,166 @@
+/*
+ * Copyright (C) 2014 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.services.telephony.sip;
+
+import android.content.ComponentName;
+import android.content.Context;
+import android.net.Uri;
+import android.net.sip.SipException;
+import android.net.sip.SipManager;
+import android.net.sip.SipProfile;
+import android.telecomm.PhoneAccount;
+import android.telecomm.PhoneAccountHandle;
+import android.telecomm.TelecommManager;
+import android.util.Log;
+
+import com.android.phone.R;
+
+import java.util.List;
+import java.util.Objects;
+import java.util.concurrent.CopyOnWriteArrayList;
+
+/**
+ * Manages the {@link PhoneAccount} entries for SIP calling.
+ */
+final class SipAccountRegistry {
+ private final class AccountEntry {
+ private final SipProfile mProfile;
+
+ AccountEntry(SipProfile profile) {
+ mProfile = profile;
+ }
+
+ SipProfile getProfile() {
+ return mProfile;
+ }
+
+ boolean register(SipManager sipManager, Context context) {
+ if (VERBOSE) log("register, profile: " + mProfile);
+ try {
+ sipManager.open(
+ mProfile,
+ SipUtil.createIncomingCallPendingIntent(context, mProfile.getUriString()),
+ null);
+ TelecommManager.from(context).registerPhoneAccount(createPhoneAccount(context));
+ return true;
+ } catch (SipException e) {
+ log("register, profile: " + mProfile.getProfileName() +
+ ", exception: " + e);
+ }
+ return false;
+ }
+
+ private PhoneAccount createPhoneAccount(Context context) {
+ PhoneAccountHandle accountHandle =
+ SipUtil.createAccountHandle(context, mProfile.getUriString());
+ return PhoneAccount.builder()
+ .withAccountHandle(accountHandle)
+ .withCapabilities(PhoneAccount.CAPABILITY_CALL_PROVIDER)
+ .withHandle(Uri.parse(mProfile.getUriString()))
+ .withLabel(mProfile.getDisplayName())
+ .withShortDescription(mProfile.getDisplayName())
+ .withIconResId(R.drawable.ic_dialer_sip_black_24dp)
+ .build();
+ }
+ }
+
+ private static final String PREFIX = "[SipAccountRegistry] ";
+ private static final boolean VERBOSE = false; /* STOP SHIP if true */
+ private static final SipAccountRegistry INSTANCE = new SipAccountRegistry();
+
+ private final List<AccountEntry> mAccounts = new CopyOnWriteArrayList<>();
+
+ private SipAccountRegistry() {}
+
+ static SipAccountRegistry getInstance() {
+ return INSTANCE;
+ }
+
+ void setup(Context context) {
+ clearCurrentSipAccounts(context);
+ registerProfiles(context, null);
+ }
+
+ void addPhone(Context context, String sipUri) {
+ registerProfiles(context, sipUri);
+ }
+
+ void removePhone(Context context, String sipUri) {
+ for (AccountEntry entry : mAccounts) {
+ if (Objects.equals(sipUri, entry.getProfile().getUriString())) {
+ TelecommManager.from(context).unregisterPhoneAccount(
+ SipUtil.createAccountHandle(context, sipUri));
+ mAccounts.remove(entry);
+ break;
+ }
+ }
+ }
+
+ /**
+ * Loops through all SIP accounts from the SIP database, starts each service and registers
+ * each with the telecomm framework. If a specific sipUri is specified, this will only register
+ * the associated SIP account.
+ *
+ * @param context The context.
+ * @param sipUri A specific SIP uri to register.
+ */
+ private void registerProfiles(final Context context, final String sipUri) {
+ if (VERBOSE) log("registerProfiles, start auto registration");
+ final SipSharedPreferences sipSharedPreferences = new SipSharedPreferences(context);
+ new Thread(new Runnable() {
+ @Override
+ public void run() {
+ SipManager sipManager = SipManager.newInstance(context);
+ SipProfileDb profileDb = new SipProfileDb(context);
+ String primaryProfile = sipSharedPreferences.getPrimaryAccount();
+ List<SipProfile> sipProfileList = profileDb.retrieveSipProfileList();
+
+ for (SipProfile profile : sipProfileList) {
+ boolean isPrimaryProfile = profile.getUriString().equals(primaryProfile);
+ if (profile.getAutoRegistration() || isPrimaryProfile) {
+ if (sipUri == null || Objects.equals(sipUri, profile.getUriString())) {
+ registerAccountForProfile(profile, sipManager, context);
+ }
+ }
+ }
+ }}
+ ).start();
+ }
+
+ private void registerAccountForProfile(
+ SipProfile profile, SipManager sipManager, Context context) {
+ AccountEntry entry = new AccountEntry(profile);
+ if (entry.register(sipManager, context)) {
+ mAccounts.add(entry);
+ }
+ }
+
+ private void clearCurrentSipAccounts(Context context) {
+ ComponentName sipComponentName = new ComponentName(context, SipConnectionService.class);
+ TelecommManager telecommManager = TelecommManager.from(context);
+ List<PhoneAccountHandle> accountHandles = telecommManager.getEnabledPhoneAccounts();
+ for (PhoneAccountHandle handle : accountHandles) {
+ if (sipComponentName.equals(handle.getComponentName())) {
+ telecommManager.unregisterPhoneAccount(handle);
+ }
+ }
+ }
+
+ private void log(String message) {
+ Log.d(SipUtil.LOG_TAG, PREFIX + message);
+ }
+}
diff --git a/sip/src/com/android/services/telephony/sip/SipBroadcastReceiver.java b/sip/src/com/android/services/telephony/sip/SipBroadcastReceiver.java
index b891a6d..2adb61a 100644
--- a/sip/src/com/android/services/telephony/sip/SipBroadcastReceiver.java
+++ b/sip/src/com/android/services/telephony/sip/SipBroadcastReceiver.java
@@ -19,16 +19,12 @@
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
-import android.net.sip.SipException;
import android.net.sip.SipManager;
-import android.net.sip.SipProfile;
import android.os.Bundle;
-import android.os.UserHandle;
+import android.telecomm.PhoneAccountHandle;
import android.telecomm.TelecommManager;
import android.util.Log;
-import java.util.List;
-
/**
* Broadcast receiver that handles SIP-related intents.
*/
@@ -45,10 +41,19 @@
return;
}
+ SipAccountRegistry sipAccountRegistry = SipAccountRegistry.getInstance();
if (action.equals(SipManager.ACTION_SIP_INCOMING_CALL)) {
takeCall(context, intent);
} else if (action.equals(SipManager.ACTION_SIP_SERVICE_UP)) {
- registerAllProfiles(context);
+ sipAccountRegistry.setup(context);
+ } else if (action.equals(SipManager.ACTION_SIP_ADD_PHONE)) {
+ if (VERBOSE) log("SIP_ADD_PHONE " + intent.getStringExtra(SipManager.EXTRA_LOCAL_URI));
+ sipAccountRegistry.addPhone(context, intent.getStringExtra(SipManager.EXTRA_LOCAL_URI));
+ } else if (action.equals(SipManager.ACTION_SIP_REMOVE_PHONE)) {
+ if (VERBOSE) log("SIP_REMOVE_PHONE " +
+ intent.getStringExtra(SipManager.EXTRA_LOCAL_URI));
+ sipAccountRegistry.removePhone(
+ context, intent.getStringExtra(SipManager.EXTRA_LOCAL_URI));
} else {
if (VERBOSE) log("onReceive, action not processed: " + action);
}
@@ -56,41 +61,12 @@
private void takeCall(Context context, Intent intent) {
if (VERBOSE) log("takeCall, intent: " + intent);
-
- Bundle extras = new Bundle();
- extras.putParcelable(SipUtil.EXTRA_INCOMING_CALL_INTENT, intent);
-
- TelecommManager.from(context).addNewIncomingCall(
- SipConnectionService.getPhoneAccountHandle(context), extras);
- }
-
- private void registerAllProfiles(final Context context) {
- if (VERBOSE) log("registerAllProfiles, start auto registration");
- final SipSharedPreferences sipSharedPreferences = new SipSharedPreferences(context);
- new Thread(new Runnable() {
- @Override
- public void run() {
- SipManager sipManager = SipManager.newInstance(context);
- SipProfileDb profileDb = new SipProfileDb(context);
- String primaryProfile = sipSharedPreferences.getPrimaryAccount();
-
- List<SipProfile> sipProfileList = profileDb.retrieveSipProfileList();
-
- for (SipProfile profile : sipProfileList) {
- boolean isPrimaryProfile = profile.getUriString().equals(primaryProfile);
- if (profile.getAutoRegistration() || isPrimaryProfile) {
- if (VERBOSE) log("registerAllProfiles, profile: " + profile);
- try {
- sipManager.open(profile,
- SipUtil.createIncomingCallPendingIntent(context), null);
- } catch (SipException e) {
- log("registerAllProfiles, profile: " + profile.getProfileName() +
- ", exception: " + e);
- }
- }
- }
- }}
- ).start();
+ PhoneAccountHandle accountHandle = intent.getParcelableExtra(SipUtil.EXTRA_PHONE_ACCOUNT);
+ if (accountHandle != null) {
+ Bundle extras = new Bundle();
+ extras.putParcelable(SipUtil.EXTRA_INCOMING_CALL_INTENT, intent);
+ TelecommManager.from(context).addNewIncomingCall(accountHandle, extras);
+ }
}
private static void log(String msg) {
diff --git a/sip/src/com/android/services/telephony/sip/SipConnection.java b/sip/src/com/android/services/telephony/sip/SipConnection.java
index 2603b98..2579159 100644
--- a/sip/src/com/android/services/telephony/sip/SipConnection.java
+++ b/sip/src/com/android/services/telephony/sip/SipConnection.java
@@ -31,7 +31,7 @@
final class SipConnection extends Connection {
private static final String PREFIX = "[SipConnection] ";
- private static final boolean VERBOSE = true; /* STOP SHIP if true */
+ private static final boolean VERBOSE = false; /* STOP SHIP if true */
private static final int MSG_PRECISE_CALL_STATE_CHANGED = 1;
diff --git a/sip/src/com/android/services/telephony/sip/SipConnectionService.java b/sip/src/com/android/services/telephony/sip/SipConnectionService.java
index 8f11935..78c0440 100644
--- a/sip/src/com/android/services/telephony/sip/SipConnectionService.java
+++ b/sip/src/com/android/services/telephony/sip/SipConnectionService.java
@@ -19,16 +19,20 @@
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
+import android.net.ConnectivityManager;
+import android.net.NetworkInfo;
import android.net.sip.SipAudioCall;
import android.net.sip.SipException;
import android.net.sip.SipManager;
import android.net.sip.SipProfile;
-import android.net.Uri;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.ResultReceiver;
import android.telecomm.Connection;
import android.telecomm.ConnectionRequest;
import android.telecomm.ConnectionService;
import android.telecomm.PhoneAccountHandle;
-import android.telecomm.Response;
+import android.telecomm.PropertyPresentation;
import android.telephony.DisconnectCause;
import android.util.Log;
@@ -36,9 +40,26 @@
import com.android.internal.telephony.PhoneFactory;
import com.android.internal.telephony.sip.SipPhone;
+import java.util.List;
+import java.util.Objects;
+
public final class SipConnectionService extends ConnectionService {
+ private interface IProfileFinderCallback {
+ void onFound(SipProfile profile);
+ }
+
private static final String PREFIX = "[SipConnectionService] ";
- private static final boolean VERBOSE = true; /* STOP SHIP if true */
+ private static final boolean VERBOSE = false; /* STOP SHIP if true */
+
+ private SipProfileDb mSipProfileDb;
+ private Handler mHandler;
+
+ @Override
+ public void onCreate() {
+ mSipProfileDb = new SipProfileDb(this);
+ mHandler = new Handler();
+ super.onCreate();
+ }
static PhoneAccountHandle getPhoneAccountHandle(Context context) {
return new PhoneAccountHandle(
@@ -52,36 +73,73 @@
final ConnectionRequest request) {
if (VERBOSE) log("onCreateOutgoingConnection, request: " + request);
+ Bundle extras = request.getExtras();
+ if (extras != null && extras.getString(SipUtil.GATEWAY_PROVIDER_PACKAGE) != null) {
+ return Connection.createFailedConnection(
+ DisconnectCause.CALL_BARRED, "Cannot make a SIP call with a gateway number.");
+ }
+
+ PhoneAccountHandle accountHandle = request.getAccountHandle();
+ ComponentName sipComponentName = new ComponentName(this, SipConnectionService.class);
+ if (!Objects.equals(accountHandle.getComponentName(), sipComponentName)) {
+ return Connection.createFailedConnection(
+ DisconnectCause.OUTGOING_FAILURE, "Did not match service connection");
+ }
+
+
final SipConnection connection = new SipConnection();
+ connection.setHandle(request.getHandle(), PropertyPresentation.ALLOWED);
+ connection.setInitializing();
+ boolean attemptCall = true;
- SipProfileChooser.Callback callback = new SipProfileChooser.Callback() {
- @Override
- public void onSipChosen(SipProfile profile) {
- if (VERBOSE) log("onCreateOutgoingConnection, onSipChosen: " + profile);
- com.android.internal.telephony.Connection chosenConnection =
- createConnectionForProfile(profile, request);
- if (chosenConnection == null) {
- connection.setDisconnected(DisconnectCause.OUTGOING_CANCELED, null);
- } else {
- connection.initialize(chosenConnection);
+ if (!SipUtil.isVoipSupported(this)) {
+ SipProfileChooserDialogs.showNoVoip(this, new ResultReceiver(mHandler) {
+ @Override
+ protected void onReceiveResult(int choice, Bundle resultData) {
+ connection.setDisconnected(
+ DisconnectCause.ERROR_UNSPECIFIED, "VoIP unsupported");
+ }
+ });
+ attemptCall = false;
+ }
+
+ if (attemptCall && !isNetworkConnected()) {
+ if (VERBOSE) log("start, network not connected, dropping call");
+ SipProfileChooserDialogs.showNoInternetError(this, new ResultReceiver(mHandler) {
+ @Override
+ protected void onReceiveResult(int choice, Bundle resultData) {
+ connection.setDisconnected(DisconnectCause.OUT_OF_SERVICE, null);
+ }
+ });
+ attemptCall = false;
+ }
+
+ if (attemptCall) {
+ // The ID used for SIP-based phone account is the SIP profile Uri. Use it to find
+ // the actual profile.
+ String profileUri = accountHandle.getId();
+ findProfile(profileUri, new IProfileFinderCallback() {
+ @Override
+ public void onFound(SipProfile profile) {
+ if (profile == null) {
+ connection.setDisconnected(
+ DisconnectCause.OUTGOING_FAILURE, "SIP profile not found.");
+ connection.destroy();
+ } else {
+ com.android.internal.telephony.Connection chosenConnection =
+ createConnectionForProfile(profile, request);
+ if (chosenConnection == null) {
+ connection.setDisconnected(
+ DisconnectCause.OUTGOING_FAILURE, "Connection failed.");
+ connection.destroy();
+ } else {
+ if (VERBOSE) log("initializing connection");
+ connection.initialize(chosenConnection);
+ }
+ }
}
- }
-
- @Override
- public void onSipNotChosen() {
- if (VERBOSE) log("onCreateOutgoingConnection, onSipNotChosen");
- connection.setDisconnected(DisconnectCause.ERROR_UNSPECIFIED, null);
- }
-
- @Override
- public void onCancelCall() {
- if (VERBOSE) log("onCreateOutgoingConnection, onCancelCall");
- connection.setDisconnected(DisconnectCause.OUTGOING_CANCELED, null);
- }
- };
-
- SipProfileChooser chooser = new SipProfileChooser(this, callback);
- chooser.start(request.getHandle(), request.getExtras());
+ });
+ }
return connection;
}
@@ -121,7 +179,9 @@
sipAudioCall);
if (VERBOSE) log("onCreateIncomingConnection, new connection: " + originalConnection);
if (originalConnection != null) {
- return new SipConnection();
+ SipConnection sipConnection = new SipConnection();
+ sipConnection.initialize(originalConnection);
+ return sipConnection;
} else {
if (VERBOSE) log("onCreateIncomingConnection, takingIncomingCall failed");
return Connection.createCanceledConnection();
@@ -156,6 +216,38 @@
return null;
}
+ /**
+ * Searched for the specified profile in the SIP profile database. This can take a long time
+ * in communicating with the database, so it is done asynchronously with a separate thread and a
+ * callback interface.
+ */
+ private void findProfile(final String profileUri, final IProfileFinderCallback callback) {
+ if (VERBOSE) log("findProfile");
+ new Thread(new Runnable() {
+ @Override
+ public void run() {
+ SipProfile profileToUse = null;
+ List<SipProfile> profileList = mSipProfileDb.retrieveSipProfileList();
+ if (profileList != null) {
+ for (SipProfile profile : profileList) {
+ if (Objects.equals(profileUri, profile.getUriString())) {
+ profileToUse = profile;
+ break;
+ }
+ }
+ }
+
+ final SipProfile profileFound = profileToUse;
+ mHandler.post(new Runnable() {
+ @Override
+ public void run() {
+ callback.onFound(profileFound);
+ }
+ });
+ }
+ }).start();
+ }
+
private SipPhone findPhoneForProfile(SipProfile profile) {
if (VERBOSE) log("findPhoneForProfile, profile: " + profile);
for (Connection connection : getAllConnections()) {
@@ -175,7 +267,7 @@
if (VERBOSE) log("createPhoneForProfile, profile: " + profile);
try {
SipManager.newInstance(this).open(profile);
- return (SipPhone) PhoneFactory.makeSipPhone(profile.getUriString());
+ return PhoneFactory.makeSipPhone(profile.getUriString());
} catch (SipException e) {
log("createPhoneForProfile, exception: " + e);
return null;
@@ -197,11 +289,17 @@
}
}
- private ConnectionRequest getConnectionRequestForIncomingCall(ConnectionRequest request,
- com.android.internal.telephony.Connection connection) {
- Uri uri = Uri.fromParts(SipUtil.SCHEME_SIP, connection.getAddress(), null);
- return new ConnectionRequest(request.getAccountHandle(), uri,
- connection.getNumberPresentation(), request.getExtras(), 0);
+ private boolean isNetworkConnected() {
+ ConnectivityManager cm =
+ (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE);
+ if (cm != null) {
+ NetworkInfo ni = cm.getActiveNetworkInfo();
+ if (ni != null && ni.isConnected()) {
+ return ni.getType() == ConnectivityManager.TYPE_WIFI ||
+ !SipManager.isSipWifiOnly(this);
+ }
+ }
+ return false;
}
private static void log(String msg) {
diff --git a/sip/src/com/android/services/telephony/sip/SipEditor.java b/sip/src/com/android/services/telephony/sip/SipEditor.java
index 2f2bdef..b35f28c 100644
--- a/sip/src/com/android/services/telephony/sip/SipEditor.java
+++ b/sip/src/com/android/services/telephony/sip/SipEditor.java
@@ -52,7 +52,7 @@
public class SipEditor extends PreferenceActivity
implements Preference.OnPreferenceChangeListener {
private static final String PREFIX = "[SipEditor] ";
- private static final boolean VERBOSE = true; /* STOP SHIP if true */
+ private static final boolean VERBOSE = false; /* STOP SHIP if true */
private static final int MENU_SAVE = Menu.FIRST;
private static final int MENU_DISCARD = Menu.FIRST + 1;
@@ -249,7 +249,8 @@
mProfileDb.saveProfile(p);
if (p.getAutoRegistration() || mSharedPreferences.isPrimaryAccount(p.getUriString())) {
try {
- mSipManager.open(p, SipUtil.createIncomingCallPendingIntent(this), null);
+ mSipManager.open(
+ p, SipUtil.createIncomingCallPendingIntent(this, p.getUriString()), null);
} catch (Exception e) {
log("saveAndRegisterProfile, register failed for profile: " + p.getUriString() +
", exception: " + e);
diff --git a/sip/src/com/android/services/telephony/sip/SipProfileChooser.java b/sip/src/com/android/services/telephony/sip/SipProfileChooser.java
deleted file mode 100644
index 687edfa..0000000
--- a/sip/src/com/android/services/telephony/sip/SipProfileChooser.java
+++ /dev/null
@@ -1,259 +0,0 @@
-/*
- * Copyright (C) 2014 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.services.telephony.sip;
-
-import android.content.Context;
-import android.content.DialogInterface;
-import android.content.Intent;
-import android.net.ConnectivityManager;
-import android.net.NetworkInfo;
-import android.net.sip.SipProfile;
-import android.net.sip.SipManager;
-import android.net.Uri;
-import android.os.Bundle;
-import android.os.Handler;
-import android.os.ResultReceiver;
-import android.provider.Settings;
-import android.telephony.PhoneNumberUtils;
-import android.telephony.TelephonyManager;
-import android.util.Log;
-
-import java.util.List;
-
-/** Find a SIP profile to use for the an outgoing call. */
-final class SipProfileChooser {
- private static final String PREFIX = "[SipProfileChooser] ";
- private static final boolean VERBOSE = true; /* STOP SHIP if true */
-
- interface Callback {
- // Call will be completed by the given SIP profile.
- void onSipChosen(SipProfile profile);
- // Call will be tried by another connection service (GSM, CDMA, etc...).
- void onSipNotChosen();
- // Call will be aborted.
- void onCancelCall();
- }
-
- private final Context mContext;
- private final Callback mCallback;
- private final SipProfileDb mSipProfileDb;
- private List<SipProfile> mProfileList;
- private SipProfile mPrimaryProfile;
- private final Handler mHandler = new Handler();
-
- SipProfileChooser(Context context, Callback callback) {
- mContext = context;
- mCallback = callback;
- mSipProfileDb = new SipProfileDb(mContext);
- }
-
- void start(Uri handle, Bundle extras) {
- if (VERBOSE) log("start, handle: " + handle);
-
- String scheme = handle.getScheme();
- if (!SipUtil.SCHEME_SIP.equals(scheme) && !SipUtil.SCHEME_TEL.equals(scheme)) {
- if (VERBOSE) log("start, unknown scheme");
- mCallback.onSipNotChosen();
- return;
- }
-
- String phoneNumber = handle.getSchemeSpecificPart();
- // Consider "tel:[email protected]" a SIP number.
- boolean isSipNumber = SipUtil.SCHEME_SIP.equals(scheme) ||
- PhoneNumberUtils.isUriNumber(phoneNumber);
- if (!SipUtil.isVoipSupported(mContext)) {
- if (isSipNumber) {
- if (VERBOSE) log("start, VOIP not supported, dropping call");
- SipProfileChooserDialogs.showNoVoip(mContext, new ResultReceiver(mHandler) {
- @Override
- protected void onReceiveResult(int choice, Bundle resultData) {
- mCallback.onCancelCall();
- }
- });
- } else {
- if (VERBOSE) log("start, VOIP not supported");
- mCallback.onSipNotChosen();
- }
- return;
- }
-
- // Don't use SIP for numbers modified by a gateway.
- if (extras != null && extras.getString(SipUtil.GATEWAY_PROVIDER_PACKAGE) != null) {
- if (VERBOSE) log("start, not using SIP for numbers modified by gateway");
- mCallback.onSipNotChosen();
- return;
- }
-
- if (!isNetworkConnected()) {
- if (isSipNumber) {
- if (VERBOSE) log("start, network not connected, dropping call");
- SipProfileChooserDialogs.showNoInternetError(mContext,
- new ResultReceiver(mHandler) {
- @Override
- protected void onReceiveResult(int choice, Bundle resultData) {
- mCallback.onCancelCall();
- }
- });
- } else {
- if (VERBOSE) log("start, network not connected");
- mCallback.onSipNotChosen();
- }
- return;
- }
-
- // Only ask user to pick SIP or Cell if they're actually connected to a cell network.
- SipSharedPreferences sipPreferences = new SipSharedPreferences(mContext);
- String callOption = sipPreferences.getSipCallOption();
- if (callOption.equals(Settings.System.SIP_ASK_ME_EACH_TIME) && !isSipNumber &&
- isInCellNetwork()) {
- if (VERBOSE) log("start, call option set to ask, asking");
- ResultReceiver receiver = new ResultReceiver(mHandler) {
- @Override
- protected void onReceiveResult(int choice, Bundle resultData) {
- if (choice == DialogInterface.BUTTON_NEGATIVE) {
- mCallback.onCancelCall();
- } else if (SipProfileChooserDialogs.isSelectedPhoneTypeSip(mContext,
- choice)) {
- buildProfileList();
- } else {
- mCallback.onSipNotChosen();
- }
- }
- };
- SipProfileChooserDialogs.showSelectPhoneType(mContext, receiver);
- return;
- }
-
- if (callOption.equals(Settings.System.SIP_ADDRESS_ONLY) && !isSipNumber) {
- if (VERBOSE) log("start, call option set to SIP only, not a sip number");
- mCallback.onSipNotChosen();
- return;
- }
-
- if ((mSipProfileDb.getProfilesCount() == 0) && !isSipNumber) {
- if (VERBOSE) log("start, no SIP accounts and not sip number");
- mCallback.onSipNotChosen();
- return;
- }
-
- if (VERBOSE) log("start, building profile list");
- buildProfileList();
- }
-
- private boolean isNetworkConnected() {
- ConnectivityManager cm = (ConnectivityManager) mContext.getSystemService(
- Context.CONNECTIVITY_SERVICE);
- if (cm != null) {
- NetworkInfo ni = cm.getActiveNetworkInfo();
- if (ni != null && ni.isConnected()) {
- return ni.getType() == ConnectivityManager.TYPE_WIFI ||
- !SipManager.isSipWifiOnly(mContext);
- }
- }
- return false;
- }
-
- private boolean isInCellNetwork() {
- TelephonyManager telephonyManager = (TelephonyManager) mContext.getSystemService(
- Context.TELEPHONY_SERVICE);
- if (telephonyManager != null) {
- // We'd also like to check the radio's power state but there's no public API to do this.
- int phoneType = telephonyManager.getPhoneType();
- return phoneType != TelephonyManager.PHONE_TYPE_NONE &&
- phoneType != TelephonyManager.PHONE_TYPE_SIP;
- }
- return false;
- }
-
- private void buildProfileList() {
- if (VERBOSE) log("buildProfileList");
- final SipSharedPreferences preferences = new SipSharedPreferences(mContext);
- new Thread(new Runnable() {
- @Override
- public void run() {
- mProfileList = mSipProfileDb.retrieveSipProfileList();
- if (mProfileList != null) {
- String primarySipUri = preferences.getPrimaryAccount();
- for (SipProfile profile : mProfileList) {
- if (profile.getUriString().equals(primarySipUri)) {
- mPrimaryProfile = profile;
- break;
- }
- }
- }
- mHandler.post(new Runnable() {
- @Override
- public void run() {
- onBuildProfileListDone();
- }
- });
- }
- }).start();
- }
-
- /**
- * At this point we definitely want to make a SIP call, we just need to figure out which
- * profile to use.
- */
- private void onBuildProfileListDone() {
- if (VERBOSE) log("onBuildProfileListDone");
- if (mProfileList == null || mProfileList.size() == 0) {
- if (VERBOSE) log("onBuildProfileListDone, no profiles, showing settings dialog");
- ResultReceiver receiver = new ResultReceiver(mHandler) {
- @Override
- protected void onReceiveResult(int choice, Bundle resultData) {
- if (choice == DialogInterface.BUTTON_POSITIVE) {
- openSipSettings();
- }
- mCallback.onCancelCall();
- }
- };
- SipProfileChooserDialogs.showStartSipSettings(mContext, receiver);
- } else if (mPrimaryProfile == null) {
- if (VERBOSE) log("onBuildProfileListDone, no primary profile, showing select dialog");
- ResultReceiver receiver = new ResultReceiver(mHandler) {
- @Override
- protected void onReceiveResult(int choice, Bundle resultData) {
- if (choice >= 0 && choice < mProfileList.size()) {
- SipProfile profile = mProfileList.get(choice);
- if (SipProfileChooserDialogs.shouldMakeSelectedProflePrimary(mContext,
- resultData)) {
- SipSharedPreferences pref = new SipSharedPreferences(mContext);
- pref.setPrimaryAccount(profile.getUriString());
- }
- mCallback.onSipChosen(profile);
- } else {
- mCallback.onCancelCall();
- }
- }
- };
- SipProfileChooserDialogs.showSelectProfile(mContext, mProfileList, receiver);
- } else {
- mCallback.onSipChosen(mPrimaryProfile);
- }
- }
-
- private void openSipSettings() {
- Intent newIntent = new Intent(mContext, SipSettings.class);
- newIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
- mContext.startActivity(newIntent);
- }
-
- private static void log(String msg) {
- Log.d(SipUtil.LOG_TAG, PREFIX + msg);
- }
-}
diff --git a/sip/src/com/android/services/telephony/sip/SipProfileChooserDialogs.java b/sip/src/com/android/services/telephony/sip/SipProfileChooserDialogs.java
index 3ba633e..4eb9762 100644
--- a/sip/src/com/android/services/telephony/sip/SipProfileChooserDialogs.java
+++ b/sip/src/com/android/services/telephony/sip/SipProfileChooserDialogs.java
@@ -41,7 +41,7 @@
implements DialogInterface.OnClickListener,
DialogInterface.OnCancelListener, CompoundButton.OnCheckedChangeListener {
private static final String PREFIX = "[SipProfileChooserDialogs] ";
- private static final boolean VERBOSE = true; /* STOP SHIP if true */
+ private static final boolean VERBOSE = false; /* STOP SHIP if true */
private static final String EXTRA_RESULT_RECEIVER = "result_receiver";
private static final String EXTRA_DIALOG_ID = "dialog_id";
diff --git a/sip/src/com/android/services/telephony/sip/SipProfileDb.java b/sip/src/com/android/services/telephony/sip/SipProfileDb.java
index 7533d16..00e214f 100644
--- a/sip/src/com/android/services/telephony/sip/SipProfileDb.java
+++ b/sip/src/com/android/services/telephony/sip/SipProfileDb.java
@@ -37,7 +37,7 @@
*/
class SipProfileDb {
private static final String PREFIX = "[SipProfileDb] ";
- private static final boolean VERBOSE = true; /* STOP SHIP if true */
+ private static final boolean VERBOSE = false; /* STOP SHIP if true */
private static final String PROFILES_DIR = "/profiles/";
private static final String PROFILE_OBJ_FILE = ".pobj";
diff --git a/sip/src/com/android/services/telephony/sip/SipSettings.java b/sip/src/com/android/services/telephony/sip/SipSettings.java
index f799f75..f6e6101 100644
--- a/sip/src/com/android/services/telephony/sip/SipSettings.java
+++ b/sip/src/com/android/services/telephony/sip/SipSettings.java
@@ -56,7 +56,7 @@
*/
public class SipSettings extends PreferenceActivity {
private static final String PREFIX = "[SipSettings] ";
- private static final boolean VERBOSE = true; /* STOP SHIP if true */
+ private static final boolean VERBOSE = false; /* STOP SHIP if true */
public static final String SIP_SHARED_PREFERENCES = "SIP_PREFERENCES";
@@ -227,7 +227,8 @@
p = updateAutoRegistrationFlag(p, enabled);
try {
if (enabled) {
- mSipManager.open(p, SipUtil.createIncomingCallPendingIntent(this), null);
+ mSipManager.open(
+ p, SipUtil.createIncomingCallPendingIntent(this, sipUri), null);
} else {
mSipManager.close(sipUri);
if (mSipSharedPreferences.isPrimaryAccount(sipUri)) {
diff --git a/sip/src/com/android/services/telephony/sip/SipSharedPreferences.java b/sip/src/com/android/services/telephony/sip/SipSharedPreferences.java
index ffb1513..ff7a3c8 100644
--- a/sip/src/com/android/services/telephony/sip/SipSharedPreferences.java
+++ b/sip/src/com/android/services/telephony/sip/SipSharedPreferences.java
@@ -29,7 +29,7 @@
*/
public class SipSharedPreferences {
private static final String PREFIX = "[SipSharedPreferences] ";
- private static final boolean VERBOSE = true; /* STOP SHIP if true */
+ private static final boolean VERBOSE = false; /* STOP SHIP if true */
private static final String SIP_SHARED_PREFERENCES = "SIP_PREFERENCES";
private static final String KEY_PRIMARY_ACCOUNT = "primary";
diff --git a/sip/src/com/android/services/telephony/sip/SipUtil.java b/sip/src/com/android/services/telephony/sip/SipUtil.java
index 7a1fcf7..3d1be3d 100644
--- a/sip/src/com/android/services/telephony/sip/SipUtil.java
+++ b/sip/src/com/android/services/telephony/sip/SipUtil.java
@@ -17,15 +17,19 @@
package com.android.services.telephony.sip;
import android.app.PendingIntent;
+import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.net.sip.SipManager;
+import android.telecomm.PhoneAccountHandle;
import android.telecomm.TelecommManager;
public class SipUtil {
static final String LOG_TAG = "SIP";
static final String EXTRA_INCOMING_CALL_INTENT =
"com.android.services.telephony.sip.incoming_call_intent";
+ static final String EXTRA_PHONE_ACCOUNT =
+ "com.android.services.telephony.sip.phone_account";
static final String GATEWAY_PROVIDER_PACKAGE =
"com.android.phone.extra.GATEWAY_PROVIDER_PACKAGE";
static final String SCHEME_TEL = "tel";
@@ -48,11 +52,12 @@
return sIsVoipSupported;
}
- static PendingIntent createIncomingCallPendingIntent(Context context) {
+ static PendingIntent createIncomingCallPendingIntent(
+ Context context, String sipUri) {
Intent intent = new Intent(context, SipBroadcastReceiver.class);
intent.setAction(SipManager.ACTION_SIP_INCOMING_CALL);
- return PendingIntent.getBroadcast(context, 0, intent,
- PendingIntent.FLAG_UPDATE_CURRENT);
+ intent.putExtra(EXTRA_PHONE_ACCOUNT, SipUtil.createAccountHandle(context, sipUri));
+ return PendingIntent.getBroadcast(context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
}
static boolean isPhoneIdle(Context context) {
@@ -63,4 +68,12 @@
}
return true;
}
+
+ /**
+ * Creates a {@link PhoneAccountHandle} from the specified SIP URI.
+ */
+ static PhoneAccountHandle createAccountHandle(Context context, String sipUri) {
+ return new PhoneAccountHandle(
+ new ComponentName(context, SipConnectionService.class), sipUri);
+ }
}
diff --git a/src/com/android/services/telephony/TelecommAccountRegistry.java b/src/com/android/services/telephony/TelecommAccountRegistry.java
index 0770f14..fedbf6b 100644
--- a/src/com/android/services/telephony/TelecommAccountRegistry.java
+++ b/src/com/android/services/telephony/TelecommAccountRegistry.java
@@ -149,7 +149,7 @@
}
/**
- * Sets up all the phone accounts for SIM and SIP accounts on first boot.
+ * Sets up all the phone accounts for SIMs on first boot.
*/
void setupOnBoot() {
IntentFilter intentFilter =
@@ -173,9 +173,20 @@
return new PhoneAccountHandle(pstnConnectionServiceName, id);
}
+ private void clearCurrentTelephonyAccounts() {
+ ComponentName telephonyComponentName =
+ new ComponentName(mContext, TelephonyConnectionService.class);
+ List<PhoneAccountHandle> accountHandles = mTelecommManager.getEnabledPhoneAccounts();
+ for (PhoneAccountHandle handle : accountHandles) {
+ if (telephonyComponentName.equals(handle.getComponentName())) {
+ mTelecommManager.unregisterPhoneAccount(handle);
+ }
+ }
+ }
+
private void setupAccounts() {
// Before we do anything, we need to clear whatever entries we registered at boot.
- mTelecommManager.clearAccounts(mContext.getPackageName());
+ clearCurrentTelephonyAccounts();
// Use counter to keep track of which default icon we are using
int currAccountIcon = 0;