Merge "Add null checks to MissedCallNotifier." into lmp-dev
diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index de59c06..a85710e 100644
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -33,6 +33,12 @@
<uses-permission android:name="android.permission.STOP_APP_SWITCHES" />
<uses-permission android:name="android.permission.VIBRATE" />
<uses-permission android:name="android.permission.WRITE_CALL_LOG" />
+ <!-- Protects the ability to register any PhoneAccount with a capability flags of either
+ PhoneAccount#CAPABILITY_CALL_PROVIDER or PhoneAccount#CAPABILITY_SIM_SUBSCRIPTION. -->
+ <permission
+ android:name="com.android.telecomm.permission.REGISTER_PROVIDER_OR_SUBSCRIPTION"
+ android:label="Register CALL_PROVIDER or SIM_SUBSCRIPTION PhoneAccount"
+ android:protectionLevel="signature"/>
<!-- Declare which SDK level this application was built against. This is needed so that IDEs
can check for incompatible APIs. -->
@@ -130,7 +136,7 @@
CALL_PRIVILEGED permission or the broadcast will not be processed. High priority of
1000 is used in all intent filters to prevent anything but the system from processing
this intent (b/8871505). -->
- <!-- TODO(santoscordon): Is there really a notion of an emergency SIP number? If not, can
+ <!-- TODO: Is there really a notion of an emergency SIP number? If not, can
that scheme be removed from this activity? -->
<activity-alias android:name="EmergencyCallActivity"
android:targetActivity="CallActivity"
diff --git a/res/values-fa/strings.xml b/res/values-fa/strings.xml
index 2bf055c..f59039e 100644
--- a/res/values-fa/strings.xml
+++ b/res/values-fa/strings.xml
@@ -38,7 +38,7 @@
<string name="respond_via_sms_confirmation_format" msgid="7229149977515784269">"پیام به <xliff:g id="PHONE_NUMBER">%s</xliff:g> ارسال شد."</string>
<string name="phone_account_preferences_title" msgid="3932310998135189661">"تنظیمات برگزیده حساب تلفن"</string>
<string name="default_outgoing_account_title" msgid="8261079649574578970">"حساب خروجی پیشفرض"</string>
- <string name="sim_call_manager_account" msgid="2559930293628077755">"حساب برقراری تماس با Wi-Fi"</string>
+ <string name="sim_call_manager_account" msgid="2559930293628077755">"حساب برقراری تماس تلفنی با Wi-Fi"</string>
<string name="account_ask_every_time" msgid="944077828070287407">"هر بار پرسیده شود"</string>
- <string name="do_not_use_sim_call_manager" msgid="5519252524007323694">"از تماس با Wi-Fi استفاده نشود"</string>
+ <string name="do_not_use_sim_call_manager" msgid="5519252524007323694">"از تماس تلفنی با Wi-Fi استفاده نشود"</string>
</resources>
diff --git a/src/com/android/telecomm/Call.java b/src/com/android/telecomm/Call.java
index d6373a1..16dc323 100644
--- a/src/com/android/telecomm/Call.java
+++ b/src/com/android/telecomm/Call.java
@@ -22,10 +22,12 @@
import android.net.Uri;
import android.os.Bundle;
import android.os.Handler;
+import android.telecomm.CallCapabilities;
import android.telecomm.CallPropertyPresentation;
import android.telecomm.CallState;
import android.telecomm.Connection;
import android.telecomm.ConnectionRequest;
+import android.telecomm.ConnectionService.VideoCallProvider;
import android.telecomm.GatewayInfo;
import android.telecomm.ParcelableConnection;
import android.telecomm.PhoneAccount;
@@ -44,6 +46,7 @@
import com.android.telecomm.ContactsAsyncHelper.OnImageLoadCompleteListener;
import com.google.common.base.Preconditions;
+import java.util.ArrayList;
import java.util.Collections;
import java.util.LinkedList;
import java.util.List;
@@ -85,6 +88,8 @@
void onStartActivityFromInCall(Call call, PendingIntent intent);
void onTargetPhoneAccountChanged(Call call);
void onConnectionManagerPhoneAccountChanged(Call call);
+ void onPhoneAccountChanged(Call call);
+ void onConferenceableCallsChanged(Call call);
}
abstract static class ListenerBase implements Listener {
@@ -134,6 +139,10 @@
public void onTargetPhoneAccountChanged(Call call) {}
@Override
public void onConnectionManagerPhoneAccountChanged(Call call) {}
+ @Override
+ public void onPhoneAccountChanged(Call call) {}
+ @Override
+ public void onConferenceableCallsChanged(Call call) {}
}
private static final OnQueryCompleteListener sCallerInfoQueryListener =
@@ -187,6 +196,10 @@
private final Handler mHandler = new Handler();
+ private final List<Call> mConferenceableCalls = new ArrayList<>();
+
+ private PhoneAccountHandle mPhoneAccountHandle;
+
private long mConnectTimeMillis;
/** The state of the call. */
@@ -312,7 +325,8 @@
}
/** {@inheritDoc} */
- @Override public String toString() {
+ @Override
+ public String toString() {
String component = null;
if (mConnectionService != null && mConnectionService.getComponentName() != null) {
component = mConnectionService.getComponentName().flattenToShortString();
@@ -513,8 +527,9 @@
}
void setCallCapabilities(int callCapabilities) {
+ Log.v(this, "setCallCapabilities: %s", CallCapabilities.toString(callCapabilities));
if (mCallCapabilities != callCapabilities) {
- mCallCapabilities = callCapabilities;
+ mCallCapabilities = callCapabilities;
for (Listener l : mListeners) {
l.onCallCapabilitiesChanged(this);
}
@@ -566,15 +581,15 @@
if (mDirectToVoicemailQueryPending) {
if (mCallerInfo != null && mCallerInfo.shouldSendToVoicemail) {
Log.i(this, "Directing call to voicemail: %s.", this);
- // TODO(santoscordon): Once we move State handling from CallsManager to Call, we
+ // TODO: Once we move State handling from CallsManager to Call, we
// will not need to set RINGING state prior to calling reject.
setState(CallState.RINGING);
reject(false, null);
} else {
- // TODO(santoscordon): Make this class (not CallsManager) responsible for changing
+ // TODO: Make this class (not CallsManager) responsible for changing
// the call state to RINGING.
- // TODO(santoscordon): Replace this with state transition to RINGING.
+ // TODO: Replace this with state transition to RINGING.
for (Listener l : mListeners) {
l.onSuccessfulIncomingCall(this);
}
@@ -597,6 +612,7 @@
@Override
public void handleCreateConnectionSuccessful(
ConnectionRequest request, ParcelableConnection connection) {
+ Log.v(this, "handleCreateConnectionSuccessful %s", connection);
mCreateConnectionProcessor = null;
setState(getStateFromConnectionState(connection.getState()));
setTargetPhoneAccount(connection.getPhoneAccount());
@@ -841,7 +857,7 @@
}
void splitFromConference() {
- // TODO(santoscordon): todo
+ // TODO: todo
}
void swapWithBackgroundCall() {
@@ -869,6 +885,15 @@
}
}
+ void setConferenceableCalls(List<Call> conferenceableCalls) {
+ mConferenceableCalls.clear();
+ mConferenceableCalls.addAll(conferenceableCalls);
+ }
+
+ List<Call> getConferenceableCalls() {
+ return mConferenceableCalls;
+ }
+
private void addChildCall(Call call) {
if (!mChildCalls.contains(call)) {
mChildCalls.add(call);
diff --git a/src/com/android/telecomm/CallActivity.java b/src/com/android/telecomm/CallActivity.java
index eb65c25..607d994 100644
--- a/src/com/android/telecomm/CallActivity.java
+++ b/src/com/android/telecomm/CallActivity.java
@@ -56,7 +56,7 @@
protected void onCreate(Bundle bundle) {
super.onCreate(bundle);
- // TODO(santoscordon): This activity will be displayed until the next screen which could be
+ // TODO: This activity will be displayed until the next screen which could be
// the in-call UI and error dialog or potentially a call-type selection dialog.
// Traditionally, this has been a black screen with a spinner. We need to reevaluate if this
// is still desired and add back if necessary. Currently, the activity is set to NoDisplay
@@ -69,7 +69,7 @@
Log.d(this, " - intent = %s", intent);
Log.d(this, " - configuration = %s", configuration);
- // TODO(santoscordon): Figure out if there is something to restore from bundle.
+ // TODO: Figure out if there is something to restore from bundle.
// See OutgoingCallBroadcaster in services/Telephony for more.
processIntent(intent);
diff --git a/src/com/android/telecomm/CallAudioManager.java b/src/com/android/telecomm/CallAudioManager.java
index 979a51a..e53de84 100644
--- a/src/com/android/telecomm/CallAudioManager.java
+++ b/src/com/android/telecomm/CallAudioManager.java
@@ -74,6 +74,7 @@
if (CallsManager.getInstance().getCalls().isEmpty()) {
Log.v(this, "all calls removed, reseting system audio to default state");
setInitialAudioState(null);
+ mWasSpeakerOn = false;
}
updateAudioStreamAndMode();
}
diff --git a/src/com/android/telecomm/CallIdMapper.java b/src/com/android/telecomm/CallIdMapper.java
index 2366343..ae13860 100644
--- a/src/com/android/telecomm/CallIdMapper.java
+++ b/src/com/android/telecomm/CallIdMapper.java
@@ -85,7 +85,7 @@
void checkValidCallId(String callId) {
// Note, no need for thread check, this method is thread safe.
if (!isValidCallId(callId)) {
- // TODO(santoscordon): Re-enable this once we stop getting updates to
+ // TODO: Re-enable this once we stop getting updates to
// ConnectionServiceWrapper for remote connections.
//throw new IllegalArgumentException(
// "Invalid call ID for " + mCallIdPrefix + ": " + callId);
diff --git a/src/com/android/telecomm/CallsManager.java b/src/com/android/telecomm/CallsManager.java
index 5ce9fe8..e75a9a1 100644
--- a/src/com/android/telecomm/CallsManager.java
+++ b/src/com/android/telecomm/CallsManager.java
@@ -42,7 +42,7 @@
*/
public final class CallsManager extends Call.ListenerBase {
- // TODO(santoscordon): Consider renaming this CallsManagerPlugin.
+ // TODO: Consider renaming this CallsManagerPlugin.
interface CallsManagerListener {
void onCallAdded(Call call);
void onCallRemoved(Call call);
@@ -276,7 +276,7 @@
false /* isConference */);
call.setExtras(extras);
- // TODO(santoscordon): Move this to be a part of addCall()
+ // TODO: Move this to be a part of addCall()
call.addListener(this);
call.startCreateConnection();
}
@@ -293,6 +293,14 @@
void placeOutgoingCall(Uri handle, GatewayInfo gatewayInfo, PhoneAccountHandle accountHandle,
boolean speakerphoneOn, int videoState) {
+ // We only allow a single outgoing call at any given time. Before placing a call, make sure
+ // there doesn't already exist another outgoing call.
+ Call currentOutgoing = getFirstCallWithState(CallState.NEW, CallState.DIALING);
+ if (currentOutgoing != null) {
+ Log.i(this, "Canceling simultaneous outgoing call.");
+ return;
+ }
+
TelecommApp app = TelecommApp.getInstance();
final Uri uriHandle = (gatewayInfo == null) ? handle : gatewayInfo.getGatewayHandle();
@@ -324,7 +332,7 @@
call.setStartWithSpeakerphoneOn(speakerphoneOn);
call.setVideoState(videoState);
- // TODO(santoscordon): Move this to be a part of addCall()
+ // TODO: Move this to be a part of addCall()
call.addListener(this);
addCall(call);
@@ -357,9 +365,10 @@
/**
* Attempts to start a conference call for the specified call.
*
- * @param call The call to conference with.
+ * @param call The call to conference.
+ * @param otherCall The other call to conference with.
*/
- void conference(Call call) {
+ void conference(Call call, Call otherCall) {
Call conferenceCall = new Call(
mConnectionServiceRepository,
null /* handle */,
@@ -392,9 +401,9 @@
Log.v(this, "Holding active/dialing call %s before answering incoming call %s.",
mForegroundCall, call);
mForegroundCall.hold();
- // TODO(santoscordon): Wait until we get confirmation of the active call being
+ // TODO: Wait until we get confirmation of the active call being
// on-hold before answering the new call.
- // TODO(santoscordon): Import logic from CallManager.acceptCall()
+ // TODO: Import logic from CallManager.acceptCall()
}
for (CallsManagerListener listener : mListeners) {
@@ -694,7 +703,7 @@
private void addCall(Call call) {
mCalls.add(call);
- // TODO(santoscordon): Update mForegroundCall prior to invoking
+ // TODO: Update mForegroundCall prior to invoking
// onCallAdded for calls which immediately take the foreground (like the first call).
for (CallsManagerListener listener : mListeners) {
listener.onCallAdded(call);
@@ -737,9 +746,9 @@
// Unfortunately, in the telephony world the radio is king. So if the call notifies
// us that the call is in a particular state, we allow it even if it doesn't make
// sense (e.g., ACTIVE -> RINGING).
- // TODO(santoscordon): Consider putting a stop to the above and turning CallState
+ // TODO: Consider putting a stop to the above and turning CallState
// into a well-defined state machine.
- // TODO(santoscordon): Define expected state transitions here, and log when an
+ // TODO: Define expected state transitions here, and log when an
// unexpected transition occurs.
call.setState(newState);
@@ -759,7 +768,7 @@
private void updateForegroundCall() {
Call newForegroundCall = null;
for (Call call : mCalls) {
- // TODO(santoscordon): Foreground-ness needs to be explicitly set. No call, regardless
+ // TODO: Foreground-ness needs to be explicitly set. No call, regardless
// of its state will be foreground by default and instead the connection service should
// be notified when its calls enter and exit foreground state. Foreground will mean that
// the call should play audio and listen to microphone if it wants.
diff --git a/src/com/android/telecomm/ConnectionServiceWrapper.java b/src/com/android/telecomm/ConnectionServiceWrapper.java
index c791932..4a45902 100644
--- a/src/com/android/telecomm/ConnectionServiceWrapper.java
+++ b/src/com/android/telecomm/ConnectionServiceWrapper.java
@@ -79,7 +79,8 @@
private static final int MSG_SET_HANDLE = 19;
private static final int MSG_SET_CALLER_DISPLAY_NAME = 20;
private static final int MSG_SET_VIDEO_STATE = 21;
- private static final int MSG_START_ACTIVITY_FROM_IN_CALL = 22;
+ private static final int MSG_SET_CONFERENCEABLE_CONNECTIONS = 22;
+ private static final int MSG_START_ACTIVITY_FROM_IN_CALL = 23;
private final Handler mHandler = new Handler() {
@Override
@@ -314,6 +315,28 @@
}
break;
}
+ case MSG_SET_CONFERENCEABLE_CONNECTIONS: {
+ SomeArgs args = (SomeArgs) msg.obj;
+ try {
+ call = mCallIdMapper.getCall(args.arg1);
+ if (call != null ){
+ @SuppressWarnings("unchecked")
+ List<String> conferenceableIds = (List<String>) args.arg2;
+ List<Call> conferenceableCalls =
+ new ArrayList<>(conferenceableIds.size());
+ for (String otherId : (List<String>) args.arg2) {
+ Call otherCall = mCallIdMapper.getCall(otherId);
+ if (otherCall != null && otherCall != call) {
+ conferenceableCalls.add(otherCall);
+ }
+ }
+ call.setConferenceableCalls(conferenceableCalls);
+ }
+ } finally {
+ args.recycle();
+ }
+ break;
+ }
case MSG_START_ACTIVITY_FROM_IN_CALL: {
SomeArgs args = (SomeArgs) msg.obj;
try {
@@ -513,6 +536,17 @@
}
@Override
+ public void setConferenceableConnections(
+ String callId, List<String> conferenceableCallIds) {
+ logIncoming("setConferenceableConnections %s %s", callId, conferenceableCallIds);
+ mCallIdMapper.checkValidCallId(callId);
+ SomeArgs args = SomeArgs.obtain();
+ args.arg1 = callId;
+ args.arg2 = conferenceableCallIds;
+ mHandler.obtainMessage(MSG_SET_CONFERENCEABLE_CONNECTIONS, args).sendToTarget();
+ }
+
+ @Override
public void startActivityFromInCall(String callId, PendingIntent intent) {
logIncoming("startActivityFromInCall %s %s", callId, intent);
mCallIdMapper.checkValidCallId(callId);
@@ -860,6 +894,7 @@
// Only give remote connection services to this connection service if it is listed as
// the connection manager.
PhoneAccountHandle simCallManager = registrar.getSimCallManager();
+ Log.d(this, "queryRemoteConnectionServices finds simCallManager = %s", simCallManager);
if (simCallManager == null ||
!simCallManager.getComponentName().equals(getComponentName())) {
noRemoteServices(callback);
diff --git a/src/com/android/telecomm/CreateConnectionProcessor.java b/src/com/android/telecomm/CreateConnectionProcessor.java
index f3449ff..5a186f4 100644
--- a/src/com/android/telecomm/CreateConnectionProcessor.java
+++ b/src/com/android/telecomm/CreateConnectionProcessor.java
@@ -147,6 +147,8 @@
}
PhoneAccountHandle simCallManager =
TelecommApp.getInstance().getPhoneAccountRegistrar().getSimCallManager();
+
+ Log.d(this, "adjustAttemptsForWifi finds simCallManager = %s", simCallManager);
if (simCallManager != null &&
!Objects.equals(simCallManager, mAttemptRecords.get(0).targetPhoneAccount)) {
mAttemptRecords.set(
diff --git a/src/com/android/telecomm/InCallAdapter.java b/src/com/android/telecomm/InCallAdapter.java
index 0acb3f5..0e6c9df 100644
--- a/src/com/android/telecomm/InCallAdapter.java
+++ b/src/com/android/telecomm/InCallAdapter.java
@@ -161,14 +161,21 @@
case MSG_SET_AUDIO_ROUTE:
mCallsManager.setAudioRoute(msg.arg1);
break;
- case MSG_CONFERENCE:
- call = mCallIdMapper.getCall(msg.obj);
- if (call != null) {
- mCallsManager.conference(call);
- } else {
- Log.w(this, "conference, unknown call id: %s", msg.obj);
+ case MSG_CONFERENCE: {
+ SomeArgs args = (SomeArgs) msg.obj;
+ try {
+ call = mCallIdMapper.getCall(args.arg1);
+ Call otherCall = mCallIdMapper.getCall(args.arg2);
+ if (call != null && otherCall != null) {
+ mCallsManager.conference(call, otherCall);
+ } else {
+ Log.w(this, "conference, unknown call id: %s", msg.obj);
+ }
+ } finally {
+ args.recycle();
}
break;
+ }
case MSG_SPLIT_FROM_CONFERENCE:
call = mCallIdMapper.getCall(msg.obj);
if (call != null) {
@@ -293,8 +300,11 @@
}
@Override
- public void conference(String callId) {
- mHandler.obtainMessage(MSG_CONFERENCE, callId).sendToTarget();
+ public void conference(String callId, String otherCallId) {
+ SomeArgs args = SomeArgs.obtain();
+ args.arg1 = callId;
+ args.arg2 = otherCallId;
+ mHandler.obtainMessage(MSG_CONFERENCE, args).sendToTarget();
}
@Override
diff --git a/src/com/android/telecomm/InCallController.java b/src/com/android/telecomm/InCallController.java
index e12372d..c94b656 100644
--- a/src/com/android/telecomm/InCallController.java
+++ b/src/com/android/telecomm/InCallController.java
@@ -112,6 +112,11 @@
public void onTargetPhoneAccountChanged(Call call) {
updateCall(call);
}
+
+ @Override
+ public void onConferenceableCallsChanged(Call call) {
+ updateCall(call);
+ }
};
/** Maintains a binding connection to the in-call app. */
@@ -146,7 +151,7 @@
@Override
public void onCallRemoved(Call call) {
if (CallsManager.getInstance().getCalls().isEmpty()) {
- // TODO(sail): Wait for all messages to be delivered to the service before unbinding.
+ // TODO: Wait for all messages to be delivered to the service before unbinding.
unbind();
}
call.removeListener(mCallListener);
@@ -238,7 +243,7 @@
UserHandle.CURRENT)) {
Log.w(this, "Could not connect to the in-call app (%s)", component);
- // TODO(santoscordon): Implement retry or fall-back-to-default logic.
+ // TODO: Implement retry or fall-back-to-default logic.
}
}
}
@@ -336,6 +341,15 @@
String callerDisplayName = call.getCallerDisplayNamePresentation() ==
CallPropertyPresentation.ALLOWED ? call.getCallerDisplayName() : null;
+ List<Call> conferenceableCalls = call.getConferenceableCalls();
+ List<String> conferenceableCallIds = new ArrayList<String>(conferenceableCalls.size());
+ for (Call otherCall : conferenceableCalls) {
+ String otherId = mCallIdMapper.getCallId(otherCall);
+ if (otherId != null) {
+ conferenceableCallIds.add(otherId);
+ }
+ }
+
return new ParcelableCall(
callId,
state,
@@ -354,6 +368,7 @@
parentCallId,
childCallIds,
call.getStatusHints(),
- call.getVideoState());
+ call.getVideoState(),
+ conferenceableCallIds);
}
}
diff --git a/src/com/android/telecomm/InCallTonePlayer.java b/src/com/android/telecomm/InCallTonePlayer.java
index 7f08587..5ccdafa 100644
--- a/src/com/android/telecomm/InCallTonePlayer.java
+++ b/src/com/android/telecomm/InCallTonePlayer.java
@@ -193,10 +193,10 @@
return;
}
- // TODO(santoscordon): Certain CDMA tones need to check the ringer-volume state before
+ // TODO: Certain CDMA tones need to check the ringer-volume state before
// playing. See CallNotifier.InCallTonePlayer.
- // TODO(santoscordon): Some tones play through the end of a call so we need to inform
+ // TODO: Some tones play through the end of a call so we need to inform
// CallAudioManager that we want focus the same way that Ringer does.
synchronized (this) {
diff --git a/src/com/android/telecomm/MissedCallNotifier.java b/src/com/android/telecomm/MissedCallNotifier.java
index ca2c56e..9e757df 100644
--- a/src/com/android/telecomm/MissedCallNotifier.java
+++ b/src/com/android/telecomm/MissedCallNotifier.java
@@ -39,7 +39,7 @@
/**
* Creates a notification for calls that the user missed (neither answered nor rejected).
- * TODO(santoscordon): Make TelephonyManager.clearMissedCalls call into this class.
+ * TODO: Make TelephonyManager.clearMissedCalls call into this class.
* STOPSHIP: Resolve b/13769374 about moving this class to InCall.
*/
class MissedCallNotifier extends CallsManagerListenerBase {
@@ -186,7 +186,7 @@
} else if (!TextUtils.isEmpty(handle)) {
// A handle should always be displayed LTR using {@link BidiFormatter} regardless of the
// content of the rest of the notification.
- // TODO(santoscordon): Does this apply to SIP addresses?
+ // TODO: Does this apply to SIP addresses?
BidiFormatter bidiFormatter = BidiFormatter.getInstance();
return bidiFormatter.unicodeWrap(handle, TextDirectionHeuristics.LTR);
} else {
diff --git a/src/com/android/telecomm/TelecommServiceImpl.java b/src/com/android/telecomm/TelecommServiceImpl.java
index 3598422..dc7050f 100644
--- a/src/com/android/telecomm/TelecommServiceImpl.java
+++ b/src/com/android/telecomm/TelecommServiceImpl.java
@@ -44,7 +44,8 @@
* Implementation of the ITelecomm interface.
*/
public class TelecommServiceImpl extends ITelecommService.Stub {
- private static final String TELEPHONY_PACKAGE_NAME = "com.android.phone";
+ private static final String REGISTER_PROVIDER_OR_SUBSCRIPTION =
+ "com.android.telecomm.permission.REGISTER_PROVIDER_OR_SUBSCRIPTION";
/** ${inheritDoc} */
@Override
@@ -195,7 +196,7 @@
account.getAccountHandle().getComponentName().getPackageName());
if (PhoneAccountRegistrar.has(account, PhoneAccount.CAPABILITY_CALL_PROVIDER) ||
PhoneAccountRegistrar.has(account, PhoneAccount.CAPABILITY_SIM_SUBSCRIPTION)) {
- enforceModifyPermissionOrCallingPackage(TELEPHONY_PACKAGE_NAME);
+ enforceRegisterProviderOrSubscriptionPermission();
}
mPhoneAccountRegistrar.registerPhoneAccount(account);
} catch (Exception e) {
@@ -410,8 +411,13 @@
}
}
+ private void enforceRegisterProviderOrSubscriptionPermission() {
+ TelecommApp.getInstance().enforceCallingOrSelfPermission(
+ REGISTER_PROVIDER_OR_SUBSCRIPTION, null);
+ }
+
private void enforceModifyPermissionOrCallingPackage(String packageName) {
- // TODO(santoscordon): Use a new telecomm permission for this instead of reusing modify.
+ // TODO: Use a new telecomm permission for this instead of reusing modify.
try {
enforceModifyPermission();
} catch (SecurityException e) {
diff --git a/tests/AndroidManifest.xml b/tests/AndroidManifest.xml
index fecfffb..bbc3292 100644
--- a/tests/AndroidManifest.xml
+++ b/tests/AndroidManifest.xml
@@ -15,10 +15,13 @@
-->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="com.android.telecomm.tests">
+ coreApp="true"
+ package="com.android.telecomm.tests">
<!-- Test connection service outgoing video preview. -->
<uses-permission android:name="android.permission.CAMERA" />
+ <uses-permission
+ android:name="com.android.telecomm.permission.REGISTER_PROVIDER_OR_SUBSCRIPTION" />
<application android:label="@string/app_name">
<uses-library android:name="android.test.runner" />
@@ -31,6 +34,12 @@
</intent-filter>
</service>
+ <service android:name="com.android.telecomm.testapps.TestConnectionManager">
+ <intent-filter>
+ <action android:name="android.telecomm.ConnectionService" />
+ </intent-filter>
+ </service>
+
<activity android:name="com.android.telecomm.testapps.TestCallActivity"
android:label="@string/testCallActivityLabel">
<intent-filter>
diff --git a/tests/res/drawable-xhdpi/stat_sys_phone_call.png b/tests/res/drawable-xhdpi/stat_sys_phone_call.png
new file mode 100644
index 0000000..1bb4340
--- /dev/null
+++ b/tests/res/drawable-xhdpi/stat_sys_phone_call.png
Binary files differ
diff --git a/tests/src/com/android/telecomm/testapps/CallServiceNotifier.java b/tests/src/com/android/telecomm/testapps/CallServiceNotifier.java
index 0dbb0b1..debfc9b 100644
--- a/tests/src/com/android/telecomm/testapps/CallServiceNotifier.java
+++ b/tests/src/com/android/telecomm/testapps/CallServiceNotifier.java
@@ -16,6 +16,8 @@
package com.android.telecomm.testapps;
+import com.android.telecomm.tests.R;
+
import android.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent;
@@ -88,19 +90,28 @@
* Registers a phone account with telecomm.
*/
public void registerPhoneAccount(Context context) {
- PhoneAccount account = new PhoneAccount(
+ TelecommManager telecommManager =
+ (TelecommManager) context.getSystemService(Context.TELECOMM_SERVICE);
+ telecommManager.registerPhoneAccount(new PhoneAccount(
new PhoneAccountHandle(
new ComponentName(context, TestConnectionService.class),
PHONE_ACCOUNT_ID),
Uri.parse("tel:555-TEST"),
"555-TEST",
PhoneAccount.CAPABILITY_CALL_PROVIDER,
- 0, // iconResId
+ R.drawable.stat_sys_phone_call,
"Dummy Service",
- "a short description for the dummy service");
- TelecommManager telecommManager =
- (TelecommManager) context.getSystemService(Context.TELECOMM_SERVICE);
- telecommManager.registerPhoneAccount(account);
+ "a short description for the dummy service"));
+ telecommManager.registerPhoneAccount(new PhoneAccount(
+ new PhoneAccountHandle(
+ new ComponentName(context, TestConnectionManager.class),
+ PHONE_ACCOUNT_ID),
+ Uri.parse("tel:555-CMGR"),
+ "555-CMGR",
+ PhoneAccount.CAPABILITY_CONNECTION_MANAGER,
+ R.drawable.stat_sys_phone_call,
+ "Dummy Connection Manager",
+ "a short description for the dummy connection manager"));
}
/**
diff --git a/tests/src/com/android/telecomm/testapps/TestConnectionManager.java b/tests/src/com/android/telecomm/testapps/TestConnectionManager.java
new file mode 100644
index 0000000..6a8433a
--- /dev/null
+++ b/tests/src/com/android/telecomm/testapps/TestConnectionManager.java
@@ -0,0 +1,203 @@
+/*
+ * 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.telecomm.testapps;
+
+import android.app.PendingIntent;
+import android.net.Uri;
+import android.telecomm.CallAudioState;
+import android.telecomm.Connection;
+import android.telecomm.ConnectionRequest;
+import android.telecomm.ConnectionService;
+import android.telecomm.PhoneAccountHandle;
+import android.telecomm.RemoteConnection;
+import android.telecomm.StatusHints;
+import android.util.Log;
+
+import java.util.Random;
+
+/**
+ * Service which acts as a fake ConnectionManager if so configured.
+ * TODO(santoscordon): Rename all classes in the directory to Dummy* (e.g., DummyConnectionService).
+ */
+public class TestConnectionManager extends ConnectionService {
+ /**
+ * Random number generator used to generate phone numbers.
+ */
+ private Random mRandom = new Random();
+
+ private final class TestManagedConnection extends Connection {
+ private final RemoteConnection.Listener mProxyListener = new RemoteConnection.Listener() {
+ @Override
+ public void onStateChanged(RemoteConnection connection, int state) {
+ setState(state);
+ }
+
+ @Override
+ public void onDisconnected(RemoteConnection connection, int cause, String message) {
+ setDisconnected(cause, message);
+ destroy();
+ }
+
+ @Override
+ public void onRequestingRingback(RemoteConnection connection, boolean ringback) {
+ setRequestingRingback(ringback);
+ }
+
+ @Override
+ public void onCallCapabilitiesChanged(RemoteConnection connection,
+ int callCapabilities) {
+ setCallCapabilities(callCapabilities);
+ }
+
+ @Override
+ public void onPostDialWait(RemoteConnection connection, String remainingDigits) {
+ setPostDialWait(remainingDigits);
+ }
+
+ @Override
+ public void onAudioModeIsVoipChanged(RemoteConnection connection, boolean isVoip) {
+ setAudioModeIsVoip(isVoip);
+ }
+
+ @Override
+ public void onStatusHintsChanged(RemoteConnection connection, StatusHints statusHints) {
+ setStatusHints(statusHints);
+ }
+
+ @Override
+ public void onVideoStateChanged(RemoteConnection connection, int videoState) {
+ setVideoState(videoState);
+ }
+
+ @Override
+ public void onHandleChanged(RemoteConnection connection, Uri handle, int presentation) {
+ setHandle(handle, presentation);
+ }
+
+ @Override
+ public void onCallerDisplayNameChanged(
+ RemoteConnection connection, String callerDisplayName, int presentation) {
+ setCallerDisplayName(callerDisplayName, presentation);
+ }
+
+ @Override
+ public void onStartActivityFromInCall(
+ RemoteConnection connection, PendingIntent intent) {
+ startActivityFromInCall(intent);
+ }
+
+ @Override
+ public void onDestroyed(RemoteConnection connection) {
+ destroy();
+ }
+ };
+
+ private final RemoteConnection mRemoteConnection;
+ private final boolean mIsIncoming;
+
+ TestManagedConnection(RemoteConnection remoteConnection, boolean isIncoming) {
+ mRemoteConnection = remoteConnection;
+ mIsIncoming = isIncoming;
+ mRemoteConnection.addListener(mProxyListener);
+ setState(mRemoteConnection.getState());
+ }
+
+ @Override
+ public void onAbort() {
+ mRemoteConnection.abort();
+ }
+
+ /** ${inheritDoc} */
+ @Override
+ public void onAnswer(int videoState) {
+ mRemoteConnection.answer(videoState);
+ }
+
+ /** ${inheritDoc} */
+ @Override
+ public void onDisconnect() {
+ mRemoteConnection.disconnect();
+ }
+
+ /** ${inheritDoc} */
+ @Override
+ public void onHold() {
+ mRemoteConnection.hold();
+ }
+
+ /** ${inheritDoc} */
+ @Override
+ public void onReject() {
+ mRemoteConnection.reject();
+ }
+
+ /** ${inheritDoc} */
+ @Override
+ public void onUnhold() {
+ mRemoteConnection.unhold();
+ }
+
+ @Override
+ public void onSetAudioState(CallAudioState state) {
+ mRemoteConnection.setAudioState(state);
+ }
+
+ private void setState(int state) {
+ log("setState: " + state);
+ switch (state) {
+ case State.ACTIVE:
+ setActive();
+ break;
+ case State.HOLDING:
+ setOnHold();
+ break;
+ case State.DIALING:
+ setDialing();
+ break;
+ case State.RINGING:
+ setRinging();
+ break;
+ }
+ }
+ }
+
+ private static void log(String msg) {
+ Log.w("telecomtestcs", "[TestConnectionService] " + msg);
+ }
+
+ @Override
+ public Connection onCreateOutgoingConnection(
+ PhoneAccountHandle connectionManagerAccount,
+ final ConnectionRequest request) {
+ return new TestManagedConnection(
+ createRemoteOutgoingConnection(
+ request.getAccountHandle(),
+ request),
+ false);
+ }
+
+ @Override
+ public Connection onCreateIncomingConnection(
+ PhoneAccountHandle connectionManagerAccount,
+ final ConnectionRequest request) {
+ return new TestManagedConnection(
+ createRemoteOutgoingConnection(
+ request.getAccountHandle(),
+ request),
+ true);
+ }
+}
diff --git a/tests/src/com/android/telecomm/testapps/TestConnectionService.java b/tests/src/com/android/telecomm/testapps/TestConnectionService.java
index 2d1084a..bd9239b 100644
--- a/tests/src/com/android/telecomm/testapps/TestConnectionService.java
+++ b/tests/src/com/android/telecomm/testapps/TestConnectionService.java
@@ -47,7 +47,7 @@
/**
* Service which provides fake calls to test the ConnectionService interface.
- * TODO(santoscordon): Rename all classes in the directory to Dummy* (e.g., DummyConnectionService).
+ * TODO: Rename all classes in the directory to Dummy* (e.g., DummyConnectionService).
*/
public class TestConnectionService extends ConnectionService {
public static final String EXTRA_GATEWAY_PROVIDER_PACKAGE =
@@ -407,7 +407,7 @@
// If the number starts with 555, then we handle it ourselves. If not, then we
// use a remote connection service.
- // TODO(santoscordon): Have a special phone number to test the account-picker dialog flow.
+ // TODO: Have a special phone number to test the account-picker dialog flow.
if (number != null && number.startsWith("555")) {
// Normally we would use the original request as is, but for testing purposes, we are
// adding ".." to the end of the number to follow its path more easily through the logs.