Merge "Permission check for ConnectionService PhoneAccounts. (2/2)" into lmp-dev
diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index 02fc1ad..7add3a8 100644
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -40,7 +40,6 @@
<protected-broadcast android:name="com.android.internal.telephony.data-restart-trysetup" />
<protected-broadcast android:name="com.android.internal.telephony.data-stall" />
- <uses-permission android:name="android.permission.BIND_CALL_SERVICE" />
<uses-permission android:name="android.permission.BROADCAST_STICKY" />
<uses-permission android:name="android.permission.CALL_PHONE" />
<uses-permission android:name="android.permission.CALL_PRIVILEGED" />
diff --git a/res/values/config.xml b/res/values/config.xml
index 0d1ae54..cfca00b 100644
--- a/res/values/config.xml
+++ b/res/values/config.xml
@@ -121,7 +121,7 @@
<!-- Show cdma auto network mode in (glabal) roaming -->
<bool name="config_show_cdma" translatable="false">false</bool>
<!-- Display enhanced 4G LTE mode menu if true -->
- <bool name="config_enhanced_4g_lte_mode_enable" translatable="false">true</bool>
+ <bool name="config_enhanced_4g_lte_mode_enable" translatable="false">false</bool>
<!-- Package name for the default in-call UI and dialer [DO NOT TRANSLATE] -->
<string name="ui_default_package" translatable="false">com.android.dialer</string>
diff --git a/sip/src/com/android/services/telephony/sip/SipConnection.java b/sip/src/com/android/services/telephony/sip/SipConnection.java
index 58db1f5..2603b98 100644
--- a/sip/src/com/android/services/telephony/sip/SipConnection.java
+++ b/sip/src/com/android/services/telephony/sip/SipConnection.java
@@ -180,11 +180,6 @@
}
@Override
- public void onChildrenChanged(List<Connection> children) {
- if (VERBOSE) log("onChildrenChanged, children: " + children);
- }
-
- @Override
public void onPhoneAccountClicked() {
if (VERBOSE) log("onPhoneAccountClicked");
}
diff --git a/sip/src/com/android/services/telephony/sip/SipConnectionService.java b/sip/src/com/android/services/telephony/sip/SipConnectionService.java
index bda564f..8f11935 100644
--- a/sip/src/com/android/services/telephony/sip/SipConnectionService.java
+++ b/sip/src/com/android/services/telephony/sip/SipConnectionService.java
@@ -61,7 +61,7 @@
com.android.internal.telephony.Connection chosenConnection =
createConnectionForProfile(profile, request);
if (chosenConnection == null) {
- connection.setCanceled();
+ connection.setDisconnected(DisconnectCause.OUTGOING_CANCELED, null);
} else {
connection.initialize(chosenConnection);
}
@@ -70,13 +70,13 @@
@Override
public void onSipNotChosen() {
if (VERBOSE) log("onCreateOutgoingConnection, onSipNotChosen");
- connection.setFailed(DisconnectCause.ERROR_UNSPECIFIED, null);
+ connection.setDisconnected(DisconnectCause.ERROR_UNSPECIFIED, null);
}
@Override
public void onCancelCall() {
if (VERBOSE) log("onCreateOutgoingConnection, onCancelCall");
- connection.setCanceled();
+ connection.setDisconnected(DisconnectCause.OUTGOING_CANCELED, null);
}
};
@@ -87,14 +87,6 @@
}
@Override
- public void onCreateConferenceConnection(
- String token,
- Connection connection,
- Response<String, Connection> response) {
- if (VERBOSE) log("onCreateConferenceConnection, connection: " + connection);
- }
-
- @Override
public Connection onCreateIncomingConnection(
PhoneAccountHandle connectionManagerAccount,
ConnectionRequest request) {
diff --git a/src/com/android/phone/MobileNetworkSettings.java b/src/com/android/phone/MobileNetworkSettings.java
index 4f038f0..89749ad 100644
--- a/src/com/android/phone/MobileNetworkSettings.java
+++ b/src/com/android/phone/MobileNetworkSettings.java
@@ -16,7 +16,6 @@
package com.android.phone;
-import com.android.ims.ImsConfig;
import com.android.ims.ImsManager;
import com.android.ims.ImsException;
import com.android.internal.telephony.Phone;
@@ -24,8 +23,6 @@
import com.android.internal.telephony.TelephonyIntents;
import com.android.internal.telephony.TelephonyProperties;
-import java.util.Map;
-
import android.app.ActionBar;
import android.app.AlertDialog;
import android.content.Context;
@@ -41,10 +38,8 @@
import android.os.SystemProperties;
import android.os.UserHandle;
import android.os.UserManager;
-import android.preference.CheckBoxPreference;
import android.preference.ListPreference;
import android.preference.Preference;
-import android.preference.Preference.OnPreferenceChangeListener;
import android.preference.PreferenceActivity;
import android.preference.PreferenceScreen;
import android.preference.SwitchPreference;
@@ -199,14 +194,6 @@
}
}
- public boolean isIMSOn() {
- SharedPreferences imsPref =
- getSharedPreferences(ImsManager.IMS_SHARED_PREFERENCES, Context.MODE_WORLD_READABLE);
-
- //return imsPref.getBoolean(ImsManager.KEY_IMS_ON, ImsManager.IMS_DEFAULT_SETTING);
- return false;
- }
-
private void setIMS(boolean turnOn) {
SharedPreferences imsPref =
getSharedPreferences(ImsManager.IMS_SHARED_PREFERENCES, Context.MODE_WORLD_READABLE);
@@ -234,7 +221,7 @@
mButton4glte = (SwitchPreference)findPreference(BUTTON_4G_LTE_KEY);
mButton4glte.setOnPreferenceChangeListener(this);
- mButton4glte.setChecked(isIMSOn());
+ mButton4glte.setChecked(ImsManager.isEnhanced4gLteModeSettingEnabledByUser(this));
try {
Context con = createPackageContext("com.android.systemui", 0);
@@ -351,6 +338,13 @@
prefSet.removePreference(pref);
}
}
+ Preference pref = prefSet.findPreference(BUTTON_4G_LTE_KEY);
+ if (pref != null) {
+ if (!ImsManager.isEnhanced4gLteModeSettingEnabledByPlatform(this)) {
+ ((SwitchPreference)pref).setChecked(false);
+ pref.setEnabled(false);
+ }
+ }
ActionBar actionBar = getActionBar();
if (actionBar != null) {
diff --git a/src/com/android/phone/NotificationMgr.java b/src/com/android/phone/NotificationMgr.java
index 39df173..6650892 100644
--- a/src/com/android/phone/NotificationMgr.java
+++ b/src/com/android/phone/NotificationMgr.java
@@ -341,7 +341,8 @@
.setContentTitle(notificationTitle)
.setContentText(notificationText)
.setContentIntent(pendingIntent)
- .setSound(ringtoneUri);
+ .setSound(ringtoneUri)
+ .setColor(mContext.getResources().getColor(R.color.dialer_theme_color));
Notification notification = builder.getNotification();
CallFeaturesSetting.migrateVoicemailVibrationSettingsIfNeeded(prefs);
@@ -428,6 +429,7 @@
final Notification.Builder builder = new Notification.Builder(mContext);
builder.setSmallIcon(android.R.drawable.stat_sys_warning);
builder.setContentTitle(mContext.getText(R.string.roaming));
+ builder.setColor(mContext.getResources().getColor(R.color.dialer_theme_color));
builder.setContentText(contentText);
builder.setContentIntent(PendingIntent.getActivity(mContext, 0, intent, 0));
diff --git a/src/com/android/services/telephony/ConferenceConnection.java b/src/com/android/services/telephony/ConferenceConnection.java
deleted file mode 100644
index 33be0be..0000000
--- a/src/com/android/services/telephony/ConferenceConnection.java
+++ /dev/null
@@ -1,74 +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;
-
-import android.telecomm.Connection;
-import android.telephony.DisconnectCause;
-
-import com.android.internal.telephony.CallStateException;
-
-import java.util.List;
-
-/**
- * Manages state for a conference call.
- */
-final class ConferenceConnection extends Connection {
- @Override
- public void onChildrenChanged(List<Connection> children) {
- if (children.isEmpty()) {
- setDisconnected(DisconnectCause.LOCAL, "conference call disconnected.");
- destroy();
- }
- }
-
- /** ${inheritDoc} */
- @Override
- public void onDisconnect() {
- // For conference-level disconnects, we need to make sure we disconnect the entire call,
- // not just one of the connections. To do this, we go through the children and get a
- // reference to the telephony-Call object and call hangup().
- for (Connection connection : getChildConnections()) {
- if (connection instanceof TelephonyConnection) {
- com.android.internal.telephony.Connection origConnection =
- ((TelephonyConnection) connection).getOriginalConnection();
- if (origConnection != null && origConnection.getCall() != null) {
- try {
- // getCall() returns what is the parent call of all conferenced conections
- // so we only need to call hangup on the main call object. Break once we've
- // done that.
- origConnection.getCall().hangup();
- break;
- } catch (CallStateException e) {
- Log.e(this, e, "Call state exception in conference hangup.");
- }
- }
- }
- }
- }
-
- /** ${inheritDoc} */
- @Override
- public void onHold() {
- for (Connection connection : getChildConnections()) {
- if (connection instanceof TelephonyConnection) {
- ((TelephonyConnection) connection).onHold();
- // Hold only needs to be called on one of the children.
- break;
- }
- }
- }
-}
diff --git a/src/com/android/services/telephony/GsmConference.java b/src/com/android/services/telephony/GsmConference.java
new file mode 100644
index 0000000..d8bc11b
--- /dev/null
+++ b/src/com/android/services/telephony/GsmConference.java
@@ -0,0 +1,123 @@
+/*
+ * 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;
+
+import android.telecomm.PhoneCapabilities;
+import android.telecomm.Conference;
+import android.telecomm.Connection;
+import android.telecomm.PhoneAccountHandle;
+
+import com.android.internal.telephony.Call;
+import com.android.internal.telephony.CallStateException;
+
+import java.util.List;
+
+/**
+ * GSM-based conference call.
+ */
+public class GsmConference extends Conference {
+
+ public GsmConference(PhoneAccountHandle phoneAccount) {
+ super(phoneAccount);
+ setCapabilities(
+ PhoneCapabilities.SUPPORT_HOLD |
+ PhoneCapabilities.HOLD |
+ PhoneCapabilities.MUTE |
+ PhoneCapabilities.SWAP_CALLS);
+ setActive();
+ }
+
+ /**
+ * Invoked when the Conference and all it's {@link Connection}s should be disconnected.
+ */
+ @Override
+ public void onDisconnect() {
+ for (Connection connection : getConnections()) {
+ Call call = getMultipartyCallForConnection(connection, "onDisconnect");
+ if (call != null) {
+ try {
+ call.hangup();
+ } catch (CallStateException e) {
+ Log.e(this, e, "Exception thrown trying to hangup conference");
+ }
+ }
+ }
+ }
+
+ /**
+ * Invoked when the specified {@link Connection} should be separated from the conference call.
+ *
+ * @param connection The connection to separate.
+ */
+ @Override
+ public void onSeparate(Connection connection) {
+ com.android.internal.telephony.Connection radioConnection =
+ getOriginalConnection(connection, "onSeparate");
+ try {
+ radioConnection.separate();
+ } catch (CallStateException e) {
+ Log.e(this, e, "Exception thrown trying to separate a conference call");
+ }
+ }
+
+ /**
+ * Invoked when the conference should be put on hold.
+ */
+ @Override
+ public void onHold() {
+ List<Connection> connections = getConnections();
+ if (connections.isEmpty()) {
+ return;
+ }
+ ((GsmConnection) connections.get(0)).performHold();
+ }
+
+ /**
+ * Invoked when the conference should be moved from hold to active.
+ */
+ @Override
+ public void onUnhold() {
+ List<Connection> connections = getConnections();
+ if (connections.isEmpty()) {
+ return;
+ }
+ ((GsmConnection) connections.get(0)).performUnhold();
+ }
+
+ private Call getMultipartyCallForConnection(Connection connection, String tag) {
+ com.android.internal.telephony.Connection radioConnection =
+ getOriginalConnection(connection, tag);
+ if (radioConnection != null) {
+ Call call = radioConnection.getCall();
+ if (call != null && call.isMultiparty()) {
+ return call;
+ }
+ }
+ return null;
+ }
+
+ private com.android.internal.telephony.Connection getOriginalConnection(
+ Connection connection, String tag) {
+
+ if (connection instanceof GsmConnection) {
+ return ((GsmConnection) connection).getOriginalConnection();
+ } else {
+ Log.e(this, null, "Non GSM connection found in a Gsm conference (%s)", tag);
+ return null;
+ }
+ }
+}
diff --git a/src/com/android/services/telephony/GsmConferenceController.java b/src/com/android/services/telephony/GsmConferenceController.java
index a69d1e6..e3d0bf5 100644
--- a/src/com/android/services/telephony/GsmConferenceController.java
+++ b/src/com/android/services/telephony/GsmConferenceController.java
@@ -17,82 +17,61 @@
package com.android.services.telephony;
import java.util.ArrayList;
-
import java.util.Collections;
+import java.util.HashSet;
import java.util.List;
+import java.util.Set;
+import android.telecomm.Conference;
import android.telecomm.Connection;
+import com.android.internal.telephony.Call;
+
/**
* Maintains a list of all the known GSM connections and implements GSM-specific conference
* call functionality.
*/
final class GsmConferenceController {
- private static GsmConferenceController sInstance;
-
private final Connection.Listener mConnectionListener = new Connection.Listener() {
@Override
public void onStateChanged(Connection c, int state) {
- // No need to recalculate for conference calls, just traditional calls.
- if (c != mGsmConferenceConnection) {
- recalculate();
- }
+ recalculate();
}
/** ${inheritDoc} */
@Override
public void onDisconnected(Connection c, int cause, String message) {
- // When a connection disconnects, make sure to release its parent reference
- // so that the parent can move to disconnected as well.
- c.setParentConnection(null);
+ recalculate();
}
};
/** The known GSM connections. */
private final List<GsmConnection> mGsmConnections = new ArrayList<>();
+ private final TelephonyConnectionService mConnectionService;
+
+ public GsmConferenceController(TelephonyConnectionService connectionService) {
+ mConnectionService = connectionService;
+ }
+
/** The GSM conference connection object. */
- private ConferenceConnection mGsmConferenceConnection;
+ private Conference mGsmConference;
- static void add(GsmConnection connection) {
- if (sInstance == null) {
- sInstance = new GsmConferenceController();
- }
- connection.addConnectionListener(sInstance.mConnectionListener);
- sInstance.mGsmConnections.add(connection);
- sInstance.recalculate();
+ void add(GsmConnection connection) {
+ mGsmConnections.add(connection);
+ connection.addConnectionListener(mConnectionListener);
+ recalculate();
}
- static void remove(GsmConnection connection) {
- if (sInstance != null) {
- connection.removeConnectionListener(sInstance.mConnectionListener);
- sInstance.mGsmConnections.remove(connection);
- sInstance.recalculate();
-
- if (sInstance.mGsmConnections.size() == 0 &&
- sInstance.mGsmConferenceConnection == null) {
- sInstance = null;
- }
- }
- }
-
- static ConferenceConnection createConferenceConnection(Connection rootConnection) {
- if (sInstance != null) {
- if (sInstance.mGsmConferenceConnection == null) {
- sInstance.mGsmConferenceConnection = new ConferenceConnection();
- Log.d(sInstance, "creating the conference connection: %s",
- sInstance.mGsmConferenceConnection);
- }
- if (rootConnection instanceof GsmConnection) {
- ((GsmConnection) rootConnection).performConference();
- }
- return sInstance.mGsmConferenceConnection;
- }
- return null;
+ void remove(GsmConnection connection) {
+ connection.removeConnectionListener(mConnectionListener);
+ mGsmConnections.remove(connection);
+ recalculate();
}
private void recalculate() {
recalculateConferenceable();
+ recalculateConference();
}
/**
@@ -141,5 +120,60 @@
for (Connection connection : backgroundConnections) {
connection.setConferenceableConnections(activeConnections);
}
+ // TODO: Do not allow conferencing of already conferenced connections.
+ }
+
+ private void recalculateConference() {
+ Set<GsmConnection> conferencedConnections = new HashSet<>();
+
+ for (GsmConnection connection : mGsmConnections) {
+ com.android.internal.telephony.Connection radioConnection =
+ connection.getOriginalConnection();
+
+ if (radioConnection != null) {
+ Call.State state = radioConnection.getState();
+ Call call = radioConnection.getCall();
+ if ((state == Call.State.ACTIVE || state == Call.State.HOLDING) &&
+ (call != null && call.isMultiparty())) {
+ conferencedConnections.add(connection);
+ }
+ }
+ }
+
+ Log.d(this, "Recalculate conference calls %s %s.",
+ mGsmConference, conferencedConnections);
+
+ if (conferencedConnections.size() < 2) {
+ Log.d(this, "less than two conference calls!");
+ // No more connections are conferenced, destroy any existing conference.
+ if (mGsmConference != null) {
+ Log.d(this, "with a conference to destroy!");
+ mGsmConference.destroy();
+ mGsmConference = null;
+ }
+ } else {
+ if (mGsmConference != null) {
+ List<Connection> existingConnections = mGsmConference.getConnections();
+ // Remove any that no longer exist
+ for (Connection connection : existingConnections) {
+ if (!conferencedConnections.contains(connection)) {
+ mGsmConference.removeConnection(connection);
+ }
+ }
+
+ // Add any new ones
+ for (Connection connection : conferencedConnections) {
+ if (!existingConnections.contains(connection)) {
+ mGsmConference.addConnection(connection);
+ }
+ }
+ } else {
+ mGsmConference = new GsmConference(null);
+ for (Connection connection : conferencedConnections) {
+ mGsmConference.addConnection(connection);
+ }
+ mConnectionService.addConference(mGsmConference);
+ }
+ }
}
}
diff --git a/src/com/android/services/telephony/GsmConnection.java b/src/com/android/services/telephony/GsmConnection.java
index 5140574..99f2cde 100644
--- a/src/com/android/services/telephony/GsmConnection.java
+++ b/src/com/android/services/telephony/GsmConnection.java
@@ -29,7 +29,6 @@
GsmConnection(Connection connection) {
super(connection);
- GsmConferenceController.add(this);
}
/** {@inheritDoc} */
@@ -55,10 +54,16 @@
}
}
- void performConference() {
+ @Override
+ public void performConference(TelephonyConnection otherConnection) {
Log.d(this, "performConference - %s", this);
if (getPhone() != null) {
try {
+ // We dont use the "other" connection because there is no concept of that in the
+ // implementation of calls inside telephony. Basically, you can "conference" and it
+ // will conference with the background call. We know that otherConnection is the
+ // background call because it would never have called setConferenceableConnections()
+ // otherwise.
getPhone().conference();
} catch (CallStateException e) {
Log.e(this, e, "Failed to conference call.");
@@ -81,6 +86,5 @@
@Override
void onRemovedFromCallService() {
super.onRemovedFromCallService();
- GsmConferenceController.remove(this);
}
}
diff --git a/src/com/android/services/telephony/TelephonyConnection.java b/src/com/android/services/telephony/TelephonyConnection.java
index 7ddb6d0..0ffb7c7 100644
--- a/src/com/android/services/telephony/TelephonyConnection.java
+++ b/src/com/android/services/telephony/TelephonyConnection.java
@@ -31,7 +31,6 @@
import com.android.internal.telephony.Phone;
import java.lang.Override;
-import java.util.List;
import java.util.Objects;
/**
@@ -204,51 +203,12 @@
@Override
public void onHold() {
- Log.v(this, "onHold");
- // TODO: Can dialing calls be put on hold as well since they take up the
- // foreground call slot?
- if (Call.State.ACTIVE == mOriginalConnectionState) {
- Log.v(this, "Holding active call");
- try {
- Phone phone = mOriginalConnection.getCall().getPhone();
- Call ringingCall = phone.getRingingCall();
-
- // Although the method says switchHoldingAndActive, it eventually calls a RIL method
- // called switchWaitingOrHoldingAndActive. What this means is that if we try to put
- // a call on hold while a call-waiting call exists, it'll end up accepting the
- // call-waiting call, which is bad if that was not the user's intention. We are
- // cheating here and simply skipping it because we know any attempt to hold a call
- // while a call-waiting call is happening is likely a request from Telecomm prior to
- // accepting the call-waiting call.
- // TODO: Investigate a better solution. It would be great here if we
- // could "fake" hold by silencing the audio and microphone streams for this call
- // instead of actually putting it on hold.
- if (ringingCall.getState() != Call.State.WAITING) {
- phone.switchHoldingAndActive();
- }
-
- // TODO: Cdma calls are slightly different.
- } catch (CallStateException e) {
- Log.e(this, e, "Exception occurred while trying to put call on hold.");
- }
- } else {
- Log.w(this, "Cannot put a call that is not currently active on hold.");
- }
+ performHold();
}
@Override
public void onUnhold() {
- Log.v(this, "onUnhold");
- if (Call.State.HOLDING == mOriginalConnectionState) {
- try {
- // TODO: This doesn't handle multiple calls across connection services yet
- mOriginalConnection.getCall().getPhone().switchHoldingAndActive();
- } catch (CallStateException e) {
- Log.e(this, e, "Exception occurred while trying to release call from hold.");
- }
- } else {
- Log.w(this, "Cannot release a call that is not already on hold from hold.");
- }
+ performUnhold();
}
@Override
@@ -288,15 +248,59 @@
}
@Override
- public void onChildrenChanged(List<Connection> children) {
- Log.v(this, "onChildrenChanged, children: " + children);
- }
-
- @Override
public void onPhoneAccountClicked() {
Log.v(this, "onPhoneAccountClicked");
}
+ public void performHold() {
+ Log.v(this, "performHold");
+ // TODO: Can dialing calls be put on hold as well since they take up the
+ // foreground call slot?
+ if (Call.State.ACTIVE == mOriginalConnectionState) {
+ Log.v(this, "Holding active call");
+ try {
+ Phone phone = mOriginalConnection.getCall().getPhone();
+ Call ringingCall = phone.getRingingCall();
+
+ // Although the method says switchHoldingAndActive, it eventually calls a RIL method
+ // called switchWaitingOrHoldingAndActive. What this means is that if we try to put
+ // a call on hold while a call-waiting call exists, it'll end up accepting the
+ // call-waiting call, which is bad if that was not the user's intention. We are
+ // cheating here and simply skipping it because we know any attempt to hold a call
+ // while a call-waiting call is happening is likely a request from Telecomm prior to
+ // accepting the call-waiting call.
+ // TODO: Investigate a better solution. It would be great here if we
+ // could "fake" hold by silencing the audio and microphone streams for this call
+ // instead of actually putting it on hold.
+ if (ringingCall.getState() != Call.State.WAITING) {
+ phone.switchHoldingAndActive();
+ }
+
+ // TODO: Cdma calls are slightly different.
+ } catch (CallStateException e) {
+ Log.e(this, e, "Exception occurred while trying to put call on hold.");
+ }
+ } else {
+ Log.w(this, "Cannot put a call that is not currently active on hold.");
+ }
+ }
+
+ public void performUnhold() {
+ Log.v(this, "performUnhold");
+ if (Call.State.HOLDING == mOriginalConnectionState) {
+ try {
+ // TODO: This doesn't handle multiple calls across connection services yet
+ mOriginalConnection.getCall().getPhone().switchHoldingAndActive();
+ } catch (CallStateException e) {
+ Log.e(this, e, "Exception occurred while trying to release call from hold.");
+ }
+ } else {
+ Log.w(this, "Cannot release a call that is not already on hold from hold.");
+ }
+ }
+
+ public void performConference(TelephonyConnection otherConnection) {}
+
protected abstract int buildCallCapabilities();
protected final void updateCallCapabilities() {
@@ -356,12 +360,8 @@
private void hangup(int disconnectCause) {
if (mOriginalConnection != null) {
try {
- Call call = mOriginalConnection.getCall();
- if (call != null && !call.isMultiparty()) {
- call.hangup();
- } else {
- mOriginalConnection.hangup();
- }
+ mOriginalConnection.hangup();
+
// Set state deliberately since we are going to close() and will no longer be
// listening to state updates from mOriginalConnection
setDisconnected(disconnectCause, null);
diff --git a/src/com/android/services/telephony/TelephonyConnectionService.java b/src/com/android/services/telephony/TelephonyConnectionService.java
index 04da3e7..dbabaa2 100644
--- a/src/com/android/services/telephony/TelephonyConnectionService.java
+++ b/src/com/android/services/telephony/TelephonyConnectionService.java
@@ -47,6 +47,8 @@
public class TelephonyConnectionService extends ConnectionService {
static String SCHEME_TEL = "tel";
+ private final GsmConferenceController mGsmConferenceController =
+ new GsmConferenceController(this);
private ComponentName mExpectedComponentName = null;
private EmergencyCallHelper mEmergencyCallHelper;
@@ -125,6 +127,7 @@
}
connection.setHandle(handle, PhoneConstants.PRESENTATION_ALLOWED);
connection.setInitializing();
+ connection.setVideoState(request.getVideoState());
if (useEmergencyCallHelper) {
if (mEmergencyCallHelper == null) {
@@ -139,7 +142,7 @@
placeOutgoingConnection(connection, phone, request);
} else {
Log.d(this, "onCreateOutgoingConnection, failed to turn on radio");
- connection.setFailed(DisconnectCause.POWER_OFF,
+ connection.setDisconnected(DisconnectCause.POWER_OFF,
"Failed to turn on radio.");
}
}
@@ -153,20 +156,6 @@
}
@Override
- public void onCreateConferenceConnection(
- String token,
- Connection connection,
- Response<String, Connection> response) {
- Log.v(this, "onCreateConferenceConnection, connection: " + connection);
- if (connection instanceof GsmConnection || connection instanceof ConferenceConnection) {
- if ((connection.getCallCapabilities() & PhoneCapabilities.MERGE_CALLS) != 0) {
- response.onResult(token,
- GsmConferenceController.createConferenceConnection(connection));
- }
- }
- }
-
- @Override
public Connection onCreateIncomingConnection(
PhoneAccountHandle connectionManagerPhoneAccount,
ConnectionRequest request) {
@@ -199,6 +188,30 @@
}
}
+ @Override
+ public void onConference(Connection connection1, Connection connection2) {
+ if (connection1 instanceof TelephonyConnection &&
+ connection2 instanceof TelephonyConnection) {
+ ((TelephonyConnection) connection1).performConference(
+ (TelephonyConnection) connection2);
+ }
+
+ }
+
+ @Override
+ public void onConnectionAdded(Connection connection) {
+ if (connection instanceof GsmConnection) {
+ mGsmConferenceController.add((GsmConnection) connection);
+ }
+ }
+
+ @Override
+ public void onConnectionRemoved(Connection connection) {
+ if (connection instanceof GsmConnection) {
+ mGsmConferenceController.remove((GsmConnection) connection);
+ }
+ }
+
private void placeOutgoingConnection(
TelephonyConnection connection, Phone phone, ConnectionRequest request) {
String number = connection.getHandle().getSchemeSpecificPart();
@@ -208,7 +221,7 @@
originalConnection = phone.dial(number, request.getVideoState());
} catch (CallStateException e) {
Log.e(this, e, "placeOutgoingConnection, phone.dial exception: " + e);
- connection.setFailed(DisconnectCause.OUTGOING_FAILURE, e.getMessage());
+ connection.setDisconnected(DisconnectCause.OUTGOING_FAILURE, e.getMessage());
return;
}
@@ -225,7 +238,7 @@
startActivity(intent);
}
Log.d(this, "placeOutgoingConnection, phone.dial returned null");
- connection.setFailed(disconnectCause, "Connection is null");
+ connection.setDisconnected(disconnectCause, "Connection is null");
} else {
connection.setOriginalConnection(originalConnection);
}