Bind self-managed calls to InCallService that support these kind of
calls.
Bug: 161144815
Test: TelecomUnitTest, manually test with test apps.
Change-Id: Ifa3566d5e681b5ab41fb3123a25fc841fa96fe60
Merged-In: Ifa3566d5e681b5ab41fb3123a25fc841fa96fe60
diff --git a/src/com/android/server/telecom/Call.java b/src/com/android/server/telecom/Call.java
index dc862ab..c5f3bde 100644
--- a/src/com/android/server/telecom/Call.java
+++ b/src/com/android/server/telecom/Call.java
@@ -44,6 +44,7 @@
import android.telecom.ConnectionService;
import android.telecom.DisconnectCause;
import android.telecom.GatewayInfo;
+import android.telecom.InCallService;
import android.telecom.Log;
import android.telecom.Logging.EventManager;
import android.telecom.ParcelableConference;
@@ -58,6 +59,7 @@
import android.telephony.TelephonyManager;
import android.telephony.emergency.EmergencyNumber;
import android.text.TextUtils;
+import android.util.ArrayMap;
import android.widget.Toast;
import com.android.internal.annotations.VisibleForTesting;
@@ -510,6 +512,15 @@
private boolean mIsSelfManaged = false;
/**
+ * Indicates whether the {@link PhoneAccount} associated with an self-managed call want to
+ * expose the call to an {@link android.telecom.InCallService} which declares the metadata
+ * {@link TelecomManager#METADATA_INCLUDE_SELF_MANAGED_CALLS},
+ * For calls that {@link #mIsSelfManaged} is {@code false}, this value should be {@code false}
+ * as well.
+ */
+ private boolean mVisibleToInCallService = false;
+
+ /**
* Indicates whether the {@link PhoneAccount} associated with this call supports video calling.
* {@code True} if the phone account supports video calling, {@code false} otherwise.
*/
@@ -1628,6 +1639,14 @@
setConnectionProperties(getConnectionProperties());
}
+ public boolean visibleToInCallService() {
+ return mVisibleToInCallService;
+ }
+
+ public void setVisibleToInCallService(boolean visibleToInCallService) {
+ mVisibleToInCallService = visibleToInCallService;
+ }
+
public void markFinishedHandoverStateAndCleanup(int handoverState) {
if (mHandoverSourceCall != null) {
mHandoverSourceCall.setHandoverState(handoverState);
@@ -3945,4 +3964,17 @@
public void setCallScreeningComponentName(String callScreeningComponentName) {
mCallScreeningComponentName = callScreeningComponentName;
}
+
+ public void maybeOnInCallServiceTrackingChanged(boolean isTracking, boolean hasUi) {
+ if (mConnectionService == null) {
+ Log.w(this, "maybeOnInCallServiceTrackingChanged() request on a call"
+ + " without a connection service.");
+ } else {
+ if (hasUi) {
+ mConnectionService.onUsingAlternativeUi(this, isTracking);
+ } else if (isTracking) {
+ mConnectionService.onTrackedByNonUiService(this, isTracking);
+ }
+ }
+ }
}
diff --git a/src/com/android/server/telecom/CallsManager.java b/src/com/android/server/telecom/CallsManager.java
index 1e963c4..b6626a0 100755
--- a/src/com/android/server/telecom/CallsManager.java
+++ b/src/com/android/server/telecom/CallsManager.java
@@ -1237,10 +1237,14 @@
PhoneAccount phoneAccount = mPhoneAccountRegistrar.getPhoneAccountUnchecked(
phoneAccountHandle);
if (phoneAccount != null) {
+ Bundle phoneAccountExtras = phoneAccount.getExtras();
call.setIsSelfManaged(phoneAccount.isSelfManaged());
if (call.isSelfManaged()) {
// Self managed calls will always be voip audio mode.
call.setIsVoipAudioMode(true);
+ call.setVisibleToInCallService(phoneAccountExtras != null
+ && phoneAccountExtras.getBoolean(
+ PhoneAccount.EXTRA_ADD_SELF_MANAGED_CALLS_TO_INCALLSERVICE, false));
} else {
// Incoming call is managed, the active call is self-managed and can't be held.
// We need to set extras on it to indicate whether answering will cause a
@@ -1259,7 +1263,6 @@
}
}
- Bundle phoneAccountExtras = phoneAccount.getExtras();
if (phoneAccountExtras != null
&& phoneAccountExtras.getBoolean(
PhoneAccount.EXTRA_ALWAYS_USE_VOIP_AUDIO_MODE)) {
@@ -1474,6 +1477,7 @@
PhoneAccount account =
mPhoneAccountRegistrar.getPhoneAccount(requestedAccountHandle, initiatingUser);
+ Bundle phoneAccountExtra = account != null ? account.getExtras() : null;
boolean isSelfManaged = account != null && account.isSelfManaged();
// Create a call with original handle. The handle may be changed when the call is attached
@@ -1504,6 +1508,9 @@
if (isSelfManaged) {
// Self-managed calls will ALWAYS use voip audio mode.
call.setIsVoipAudioMode(true);
+ call.setVisibleToInCallService(phoneAccountExtra != null
+ && phoneAccountExtra.getBoolean(
+ PhoneAccount.EXTRA_ADD_SELF_MANAGED_CALLS_TO_INCALLSERVICE, false));
}
call.setInitiatingUser(initiatingUser);
isReusedCall = false;
@@ -4740,6 +4747,9 @@
extras.putLong(TelecomManager.EXTRA_CALL_TELECOM_ROUTING_START_TIME_MILLIS,
SystemClock.elapsedRealtime());
+ if (call.visibleToInCallService()) {
+ extras.putBoolean(PhoneAccount.EXTRA_ADD_SELF_MANAGED_CALLS_TO_INCALLSERVICE, true);
+ }
call.setIntentExtras(extras);
}
diff --git a/src/com/android/server/telecom/ConnectionServiceWrapper.java b/src/com/android/server/telecom/ConnectionServiceWrapper.java
index 72c3f24..1cb3957 100755
--- a/src/com/android/server/telecom/ConnectionServiceWrapper.java
+++ b/src/com/android/server/telecom/ConnectionServiceWrapper.java
@@ -1573,6 +1573,34 @@
}
}
+ /** @see IConnectionService#onUsingAlternativeUi(String, boolean, Session.Info) */
+ @VisibleForTesting
+ public void onUsingAlternativeUi(Call activeCall, boolean isUsingAlternativeUi) {
+ final String callId = mCallIdMapper.getCallId(activeCall);
+ if (callId != null && isServiceValid("onUsingAlternativeUi")) {
+ try {
+ logOutgoing("onUsingAlternativeUi %s", isUsingAlternativeUi);
+ mServiceInterface.onUsingAlternativeUi(callId, isUsingAlternativeUi,
+ Log.getExternalSession(TELECOM_ABBREVIATION));
+ } catch (RemoteException e) {
+ }
+ }
+ }
+
+ /** @see IConnectionService#onTrackedByNonUiService(String, boolean, Session.Info) */
+ @VisibleForTesting
+ public void onTrackedByNonUiService(Call activeCall, boolean isTracked) {
+ final String callId = mCallIdMapper.getCallId(activeCall);
+ if (callId != null && isServiceValid("onTrackedByNonUiService")) {
+ try {
+ logOutgoing("onTrackedByNonUiService %s", isTracked);
+ mServiceInterface.onTrackedByNonUiService(callId, isTracked,
+ Log.getExternalSession(TELECOM_ABBREVIATION));
+ } catch (RemoteException e) {
+ }
+ }
+ }
+
/** @see IConnectionService#disconnect(String, Session.Info) */
void disconnect(Call call) {
final String callId = mCallIdMapper.getCallId(call);
diff --git a/src/com/android/server/telecom/InCallController.java b/src/com/android/server/telecom/InCallController.java
index 53ad45b..e46d377 100644
--- a/src/com/android/server/telecom/InCallController.java
+++ b/src/com/android/server/telecom/InCallController.java
@@ -113,7 +113,7 @@
public Call mCall;
}
- private class InCallServiceInfo {
+ public static class InCallServiceInfo {
private final ComponentName mComponentName;
private boolean mIsExternalCallsSupported;
private boolean mIsSelfManagedCallsSupported;
@@ -279,7 +279,8 @@
}
if (call != null && call.isSelfManaged() &&
- !mInCallServiceInfo.isSelfManagedCallsSupported()) {
+ (!mInCallServiceInfo.isSelfManagedCallsSupported()
+ || !call.visibleToInCallService())) {
Log.i(this, "Skipping binding to %s - doesn't support self-mgd calls",
mInCallServiceInfo);
mIsConnected = false;
@@ -342,6 +343,7 @@
mInCallServiceInfo.getType(),
mInCallServiceInfo.getDisconnectTime()
- mInCallServiceInfo.getBindingStartTime(), mIsNullBinding);
+ updateCallTracking(mCall, mInCallServiceInfo, false /* isAdd */);
}
InCallController.this.onDisconnected(mInCallServiceInfo);
@@ -748,6 +750,10 @@
newConnection.connect(callToConnectWith);
}
}
+
+ public List<InCallServiceBindingConnection> getSubConnections() {
+ return mSubConnections;
+ }
}
private final Call.Listener mCallListener = new Call.ListenerBase() {
@@ -915,12 +921,12 @@
@Override
public void onPackageUninstalled(String packageName) {
mCarModeTracker.forceExitCarMode(packageName);
- updateCarModeForSwitchingConnection();
+ updateCarModeForConnections();
}
};
private static final int IN_CALL_SERVICE_TYPE_INVALID = 0;
- private static final int IN_CALL_SERVICE_TYPE_DIALER_UI = 1;
+ private static final int IN_CALL_SERVICE_TYPE_DEFAULT_DIALER_UI = 1;
private static final int IN_CALL_SERVICE_TYPE_SYSTEM_UI = 2;
private static final int IN_CALL_SERVICE_TYPE_CAR_MODE_UI = 3;
private static final int IN_CALL_SERVICE_TYPE_NON_UI = 4;
@@ -967,10 +973,9 @@
private boolean mIsCallUsingMicrophone = false;
public InCallController(Context context, TelecomSystem.SyncRoot lock, CallsManager callsManager,
- SystemStateHelper systemStateHelper,
- DefaultDialerCache defaultDialerCache, Timeouts.Adapter timeoutsAdapter,
- EmergencyCallHelper emergencyCallHelper, CarModeTracker carModeTracker,
- ClockProxy clockProxy) {
+ SystemStateHelper systemStateHelper, DefaultDialerCache defaultDialerCache,
+ Timeouts.Adapter timeoutsAdapter, EmergencyCallHelper emergencyCallHelper,
+ CarModeTracker carModeTracker, ClockProxy clockProxy) {
mContext = context;
mAppOpsManager = context.getSystemService(AppOpsManager.class);
mLock = lock;
@@ -1013,12 +1018,16 @@
continue;
}
- if (call.isSelfManaged() && !info.isSelfManagedCallsSupported()) {
+ if (call.isSelfManaged() && (!call.visibleToInCallService()
+ || !info.isSelfManagedCallsSupported())) {
continue;
}
// Only send the RTT call if it's a UI in-call service
- boolean includeRttCall = info.equals(mInCallServiceConnection.getInfo());
+ boolean includeRttCall = false;
+ if (mInCallServiceConnection != null) {
+ includeRttCall = info.equals(mInCallServiceConnection.getInfo());
+ }
componentsUpdated.add(info.getComponentName());
IInCallService inCallService = entry.getValue();
@@ -1030,6 +1039,7 @@
info.getType() == IN_CALL_SERVICE_TYPE_NON_UI);
try {
inCallService.addCall(sanitizeParcelableCallForService(info, parcelableCall));
+ updateCallTracking(call, info, true /* isAdd */);
} catch (RemoteException ignored) {
}
}
@@ -1079,7 +1089,8 @@
continue;
}
- if (call.isSelfManaged() && !info.isSelfManagedCallsSupported()) {
+ if (call.isSelfManaged() && !call.visibleToInCallService()
+ && !info.isSelfManagedCallsSupported()) {
continue;
}
@@ -1096,6 +1107,7 @@
info.getType() == IN_CALL_SERVICE_TYPE_NON_UI);
try {
inCallService.addCall(sanitizeParcelableCallForService(info, parcelableCall));
+ updateCallTracking(call, info, true /* isAdd */);
} catch (RemoteException ignored) {
}
}
@@ -1356,7 +1368,8 @@
/**
* Binds to all the UI-providing InCallService as well as system-implemented non-UI
- * InCallServices. Method-invoker must check {@link #isBoundAndConnectedToServices()} before invoking.
+ * InCallServices. Method-invoker must check {@link #isBoundAndConnectedToServices()}
+ * before invoking.
*
* @param call The newly added call that triggered the binding to the in-call services.
*/
@@ -1409,7 +1422,7 @@
}
}
- private void connectToNonUiInCallServices(Call call) {
+ private void updateNonUiInCallServices() {
List<InCallServiceInfo> nonUIInCallComponents =
getInCallServiceComponents(IN_CALL_SERVICE_TYPE_NON_UI);
List<InCallServiceBindingConnection> nonUIInCalls = new LinkedList<>();
@@ -1419,7 +1432,7 @@
List<String> callCompanionApps = mCallsManager
.getRoleManagerAdapter().getCallCompanionApps();
if (callCompanionApps != null && !callCompanionApps.isEmpty()) {
- for(String pkg : callCompanionApps) {
+ for (String pkg : callCompanionApps) {
InCallServiceInfo info = getInCallServiceComponent(pkg,
IN_CALL_SERVICE_TYPE_COMPANION);
if (info != null) {
@@ -1427,7 +1440,14 @@
}
}
}
- mNonUIInCallServiceConnections = new NonUIInCallServiceConnectionCollection(nonUIInCalls);
+ mNonUIInCallServiceConnections = new NonUIInCallServiceConnectionCollection(
+ nonUIInCalls);
+ }
+
+ private void connectToNonUiInCallServices(Call call) {
+ if (mNonUIInCallServiceConnections == null) {
+ updateNonUiInCallServices();
+ }
mNonUIInCallServiceConnections.connect(call);
IntentFilter packageChangedFilter = new IntentFilter(Intent.ACTION_PACKAGE_CHANGED);
@@ -1444,7 +1464,7 @@
InCallServiceInfo defaultDialerComponent =
(systemPackageName != null && systemPackageName.equals(packageName))
? getInCallServiceComponent(packageName, IN_CALL_SERVICE_TYPE_SYSTEM_UI)
- : getInCallServiceComponent(packageName, IN_CALL_SERVICE_TYPE_DIALER_UI);
+ : getInCallServiceComponent(packageName, IN_CALL_SERVICE_TYPE_DEFAULT_DIALER_UI);
/* TODO: in Android 12 re-enable this an InCallService is required by the dialer role.
if (packageName != null && defaultDialerComponent == null) {
// The in call service of default phone app is disabled, send notification.
@@ -1494,7 +1514,6 @@
private List<InCallServiceInfo> getInCallServiceComponents(String packageName,
ComponentName componentName, int requestedType) {
-
List<InCallServiceInfo> retval = new LinkedList<>();
Intent serviceIntent = new Intent(InCallService.SERVICE_INTERFACE);
@@ -1526,13 +1545,19 @@
if (requestedType == IN_CALL_SERVICE_TYPE_NON_UI) {
mKnownNonUiInCallServices.add(foundComponentName);
}
- if (serviceInfo.enabled && (requestedType == 0 || requestedType == currentType)) {
- retval.add(new InCallServiceInfo(foundComponentName,
- isExternalCallsSupported, isSelfManageCallsSupported, requestedType));
+
+ boolean isRequestedType;
+ if (requestedType == IN_CALL_SERVICE_TYPE_INVALID) {
+ isRequestedType = true;
+ } else {
+ isRequestedType = requestedType == currentType;
+ }
+ if (serviceInfo.enabled && isRequestedType) {
+ retval.add(new InCallServiceInfo(foundComponentName, isExternalCallsSupported,
+ isSelfManageCallsSupported, requestedType));
}
}
}
-
return retval;
}
@@ -1598,7 +1623,7 @@
mDefaultDialerCache.getDefaultDialerApplication(
mCallsManager.getCurrentUserHandle().getIdentifier()));
if (isDefaultDialerPackage && isUIService) {
- return IN_CALL_SERVICE_TYPE_DIALER_UI;
+ return IN_CALL_SERVICE_TYPE_DEFAULT_DIALER_UI;
}
// Also allow any in-call service that has the control-experience permission (to ensure
@@ -1637,7 +1662,7 @@
if (info.getType() == IN_CALL_SERVICE_TYPE_CAR_MODE_UI
|| info.getType() == IN_CALL_SERVICE_TYPE_SYSTEM_UI
- || info.getType() == IN_CALL_SERVICE_TYPE_DIALER_UI) {
+ || info.getType() == IN_CALL_SERVICE_TYPE_DEFAULT_DIALER_UI) {
trackCallingUserInterfaceStarted(info);
}
IInCallService inCallService = IInCallService.Stub.asInterface(service);
@@ -1663,13 +1688,17 @@
int numCallsSent = 0;
for (Call call : calls) {
try {
- if ((call.isSelfManaged() && !info.isSelfManagedCallsSupported()) ||
+ if ((call.isSelfManaged() && (!info.isSelfManagedCallsSupported()
+ || !call.visibleToInCallService())) ||
(call.isExternalCall() && !info.isExternalCallsSupported())) {
continue;
}
// Only send the RTT call if it's a UI in-call service
- boolean includeRttCall = info.equals(mInCallServiceConnection.getInfo());
+ boolean includeRttCall = false;
+ if (mInCallServiceConnection != null) {
+ includeRttCall = info.equals(mInCallServiceConnection.getInfo());
+ }
// Track the call if we don't already know about it.
addCall(call);
@@ -1683,6 +1712,7 @@
info.getType() == IN_CALL_SERVICE_TYPE_SYSTEM_UI ||
info.getType() == IN_CALL_SERVICE_TYPE_NON_UI);
inCallService.addCall(sanitizeParcelableCallForService(info, parcelableCall));
+ updateCallTracking(call, info, true /* isAdd */);
} catch (RemoteException ignored) {
}
}
@@ -1709,7 +1739,7 @@
Log.i(this, "onDisconnected from %s", disconnectedInfo.getComponentName());
if (disconnectedInfo.getType() == IN_CALL_SERVICE_TYPE_CAR_MODE_UI
|| disconnectedInfo.getType() == IN_CALL_SERVICE_TYPE_SYSTEM_UI
- || disconnectedInfo.getType() == IN_CALL_SERVICE_TYPE_DIALER_UI) {
+ || disconnectedInfo.getType() == IN_CALL_SERVICE_TYPE_DEFAULT_DIALER_UI) {
trackCallingUserInterfaceStopped(disconnectedInfo);
}
mInCallServices.remove(disconnectedInfo);
@@ -1743,7 +1773,8 @@
continue;
}
- if (call.isSelfManaged() && !info.isSelfManagedCallsSupported()) {
+ if (call.isSelfManaged() && (!call.visibleToInCallService()
+ || !info.isSelfManagedCallsSupported())) {
continue;
}
@@ -1824,7 +1855,7 @@
*/
private ComponentName getConnectedUi() {
InCallServiceInfo connectedUi = mInCallServices.keySet().stream().filter(
- i -> i.getType() == IN_CALL_SERVICE_TYPE_DIALER_UI
+ i -> i.getType() == IN_CALL_SERVICE_TYPE_DEFAULT_DIALER_UI
|| i.getType() == IN_CALL_SERVICE_TYPE_SYSTEM_UI)
.findAny()
.orElse(null);
@@ -1942,13 +1973,13 @@
mCarModeTracker.handleExitCarMode(priority, packageName);
}
- updateCarModeForSwitchingConnection();
+ updateCarModeForConnections();
}
- public void updateCarModeForSwitchingConnection() {
+ public void updateCarModeForConnections() {
+ Log.i(this, "updateCarModeForConnections: car mode apps: %s",
+ mCarModeTracker.getCarModeApps().stream().collect(Collectors.joining(", ")));
if (mInCallServiceConnection != null) {
- Log.i(this, "updateCarModeForSwitchingConnection: car mode apps: %s",
- mCarModeTracker.getCarModeApps().stream().collect(Collectors.joining(", ")));
if (shouldUseCarModeUI()) {
mInCallServiceConnection.changeCarModeApp(
mCarModeTracker.getCurrentCarModePackage());
@@ -2058,4 +2089,11 @@
notificationManager.notify(NOTIFICATION_TAG, IN_CALL_SERVICE_NOTIFICATION_ID,
builder.build());
}
+
+ private void updateCallTracking(Call call, InCallServiceInfo info, boolean isAdd) {
+ int type = info.getType();
+ boolean hasUi = type == IN_CALL_SERVICE_TYPE_CAR_MODE_UI
+ || type == IN_CALL_SERVICE_TYPE_DEFAULT_DIALER_UI;
+ call.maybeOnInCallServiceTrackingChanged(isAdd, hasUi);
+ }
}
diff --git a/testapps/AndroidManifest.xml b/testapps/AndroidManifest.xml
index 9c461ca..891a7a7 100644
--- a/testapps/AndroidManifest.xml
+++ b/testapps/AndroidManifest.xml
@@ -70,6 +70,8 @@
android:exported="true">
<meta-data android:name="android.telecom.IN_CALL_SERVICE_UI"
android:value="true"/>
+ <meta-data android:name="android.telecom.INCLUDE_SELF_MANAGED_CALLS"
+ android:value="true" />
<intent-filter>
<action android:name="android.telecom.InCallService"/>
</intent-filter>
diff --git a/testapps/carmodedialer/AndroidManifest.xml b/testapps/carmodedialer/AndroidManifest.xml
index f237211..239726c 100644
--- a/testapps/carmodedialer/AndroidManifest.xml
+++ b/testapps/carmodedialer/AndroidManifest.xml
@@ -37,8 +37,10 @@
<service android:name="com.android.server.telecom.carmodedialer.CarModeInCallServiceImpl"
android:permission="android.permission.BIND_INCALL_SERVICE"
android:exported="true">
- <meta-data android:name="android.telecom.IN_CALL_SERVICE_CAR_MODE_UI"
- android:value="true"/>
+ <meta-data android:name="android.telecom.IN_CALL_SERVICE_CAR_MODE_UI"
+ android:value="true"/>
+ <meta-data android:name="android.telecom.INCLUDE_SELF_MANAGED_CALLS"
+ android:value="true"/>
<intent-filter>
<action android:name="android.telecom.InCallService"/>
</intent-filter>
diff --git a/testapps/res/layout/self_managed_sample_main.xml b/testapps/res/layout/self_managed_sample_main.xml
index 28f4473..d26d629 100644
--- a/testapps/res/layout/self_managed_sample_main.xml
+++ b/testapps/res/layout/self_managed_sample_main.xml
@@ -90,7 +90,6 @@
<LinearLayout android:orientation="horizontal"
android:layout_width="wrap_content"
android:layout_height="wrap_content">
-
<Button
android:id="@+id/placeOutgoingCallButton"
android:layout_width="wrap_content"
@@ -113,6 +112,35 @@
android:text="Req CallScreen Role"/>
</LinearLayout>
+ <LinearLayout android:orientation="horizontal"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content">
+ <Button
+ android:id="@+id/placeSelfManagedOutgoingCallButton"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="SelfManagedOutgoing"/>
+ <Button
+ android:id="@+id/placeSelfManagedIncomingCallButton"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="SelfManagedIncoming"/>
+ </LinearLayout>
+
+ <LinearLayout android:orientation="horizontal"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content">
+ <Button
+ android:id="@+id/enableCarMode"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="Enable car mode"/>
+ <Button
+ android:id="@+id/disableCarMode"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="Disable car mode"/>
+ </LinearLayout>
<ListView
android:id="@+id/callList"
android:layout_width="match_parent"
diff --git a/testapps/src/com/android/server/telecom/testapps/SelfManagedCallList.java b/testapps/src/com/android/server/telecom/testapps/SelfManagedCallList.java
index 4b5fa57..d4661ff 100644
--- a/testapps/src/com/android/server/telecom/testapps/SelfManagedCallList.java
+++ b/testapps/src/com/android/server/telecom/testapps/SelfManagedCallList.java
@@ -46,8 +46,10 @@
public static String SELF_MANAGED_ACCOUNT_1 = "1";
public static String SELF_MANAGED_ACCOUNT_2 = "2";
+ public static String SELF_MANAGED_ACCOUNT_3 = "3";
public static String SELF_MANAGED_NAME_1 = "SuperCall";
public static String SELF_MANAGED_NAME_2 = "Mega Call";
+ public static String SELF_MANAGED_NAME_3 = "SM Call";
public static String CUSTOM_URI_SCHEME = "custom";
private static SelfManagedCallList sInstance;
@@ -99,6 +101,8 @@
SELF_MANAGED_NAME_1, true /* areCallsLogged */);
registerPhoneAccount(context, SELF_MANAGED_ACCOUNT_2, SELF_MANAGED_ADDRESS_2,
SELF_MANAGED_NAME_2, false /* areCallsLogged */);
+ registerPhoneAccount(context, SELF_MANAGED_ACCOUNT_3, SELF_MANAGED_ADDRESS_1,
+ SELF_MANAGED_NAME_3, true /* areCallsLogged */);
}
public void registerPhoneAccount(Context context, String id, Uri address, String name,
@@ -110,6 +114,9 @@
if (areCallsLogged) {
extras.putBoolean(PhoneAccount.EXTRA_LOG_SELF_MANAGED_CALLS, true);
}
+ if (id.equals(SELF_MANAGED_ACCOUNT_3)) {
+ extras.putBoolean(PhoneAccount.EXTRA_ADD_SELF_MANAGED_CALLS_TO_INCALLSERVICE, true);
+ }
PhoneAccount.Builder builder = PhoneAccount.builder(handle, name)
.addSupportedUriScheme(PhoneAccount.SCHEME_TEL)
.addSupportedUriScheme(PhoneAccount.SCHEME_SIP)
diff --git a/testapps/src/com/android/server/telecom/testapps/SelfManagedCallingActivity.java b/testapps/src/com/android/server/telecom/testapps/SelfManagedCallingActivity.java
index fd12a2e..44410d2 100644
--- a/testapps/src/com/android/server/telecom/testapps/SelfManagedCallingActivity.java
+++ b/testapps/src/com/android/server/telecom/testapps/SelfManagedCallingActivity.java
@@ -16,9 +16,12 @@
package com.android.server.telecom.testapps;
+import static android.app.UiModeManager.DEFAULT_PRIORITY;
+
import android.app.Activity;
import android.app.NotificationChannel;
import android.app.NotificationManager;
+import android.app.UiModeManager;
import android.app.role.RoleManager;
import android.content.Intent;
import android.media.AudioAttributes;
@@ -54,9 +57,13 @@
private SelfManagedCallList mCallList = SelfManagedCallList.getInstance();
private CheckBox mCheckIfPermittedBeforeCalling;
private Button mPlaceOutgoingCallButton;
+ private Button mPlaceSelfManagedOutgoingCallButton;
+ private Button mPlaceSelfManagedIncomingCallButton;
private Button mPlaceIncomingCallButton;
private Button mHandoverFrom;
private Button mRequestCallScreeningRole;
+ private Button mEnableCarMode;
+ private Button mDisableCarMode;
private RadioButton mUseAcct1Button;
private RadioButton mUseAcct2Button;
private CheckBox mHoldableCheckbox;
@@ -119,6 +126,20 @@
placeOutgoingCall();
}
});
+ mPlaceSelfManagedOutgoingCallButton = (Button) findViewById(
+ R.id.placeSelfManagedOutgoingCallButton);
+ mPlaceSelfManagedOutgoingCallButton.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ placeSelfManagedOutgoingCall();
+ }
+ });
+ mPlaceSelfManagedIncomingCallButton = (Button) findViewById(
+ R.id.placeSelfManagedIncomingCallButton);
+ mPlaceSelfManagedIncomingCallButton.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View v) { placeSelfManagedIncomingCall(); }
+ });
mPlaceIncomingCallButton = (Button) findViewById(R.id.placeIncomingCallButton);
mPlaceIncomingCallButton.setOnClickListener(new View.OnClickListener() {
@Override
@@ -134,7 +155,14 @@
mRequestCallScreeningRole.setOnClickListener((v -> {
requestCallScreeningRole();
}));
-
+ mEnableCarMode = (Button) findViewById(R.id.enableCarMode);
+ mEnableCarMode.setOnClickListener((v -> {
+ enableCarMode();
+ }));
+ mDisableCarMode = (Button) findViewById(R.id.disableCarMode);
+ mDisableCarMode.setOnClickListener((v -> {
+ disableCarMode();
+ }));
mUseAcct1Button = findViewById(R.id.useAcct1Button);
mUseAcct2Button = findViewById(R.id.useAcct2Button);
mHasFocus = findViewById(R.id.hasFocus);
@@ -184,6 +212,25 @@
tm.placeCall(Uri.parse(mNumber.getText().toString()), extras);
}
+ private void placeSelfManagedOutgoingCall() {
+ TelecomManager tm = TelecomManager.from(this);
+ PhoneAccountHandle phoneAccountHandle = mCallList.getPhoneAccountHandle(
+ SelfManagedCallList.SELF_MANAGED_ACCOUNT_3);
+
+ if (mCheckIfPermittedBeforeCalling.isChecked()) {
+ Toast.makeText(this, R.string.outgoingCallNotPermitted, Toast.LENGTH_SHORT).show();
+ return;
+ }
+
+ Bundle extras = new Bundle();
+ extras.putParcelable(TelecomManager.EXTRA_PHONE_ACCOUNT_HANDLE, phoneAccountHandle);
+ if (mVideoCallCheckbox.isChecked()) {
+ extras.putInt(TelecomManager.EXTRA_START_CALL_WITH_VIDEO_STATE,
+ VideoProfile.STATE_BIDIRECTIONAL);
+ }
+ tm.placeCall(Uri.parse(mNumber.getText().toString()), extras);
+ }
+
private void initiateHandover() {
TelecomManager tm = TelecomManager.from(this);
PhoneAccountHandle phoneAccountHandle = getSelectedPhoneAccountHandle();
@@ -214,6 +261,37 @@
tm.addNewIncomingCall(getSelectedPhoneAccountHandle(), extras);
}
+ private void placeSelfManagedIncomingCall() {
+ TelecomManager tm = TelecomManager.from(this);
+ PhoneAccountHandle phoneAccountHandle = mCallList.getPhoneAccountHandle(
+ SelfManagedCallList.SELF_MANAGED_ACCOUNT_3);
+
+ if (mCheckIfPermittedBeforeCalling.isChecked()) {
+ if (!tm.isIncomingCallPermitted(phoneAccountHandle)) {
+ Toast.makeText(this, R.string.incomingCallNotPermitted , Toast.LENGTH_SHORT).show();
+ return;
+ }
+ }
+
+ Bundle extras = new Bundle();
+ extras.putParcelable(TelecomManager.EXTRA_INCOMING_CALL_ADDRESS,
+ Uri.parse(mNumber.getText().toString()));
+ tm.addNewIncomingCall(phoneAccountHandle, extras);
+ }
+
+ private void enableCarMode() {
+ UiModeManager uiModeManager = getSystemService(UiModeManager.class);
+ uiModeManager.enableCarMode(0);
+ Toast.makeText(this, "Enabling car mode with priority " + DEFAULT_PRIORITY,
+ Toast.LENGTH_LONG).show();
+ }
+
+ private void disableCarMode() {
+ UiModeManager uiModeManager = getSystemService(UiModeManager.class);
+ uiModeManager.disableCarMode(0);
+ Toast.makeText(this, "Disabling car mode", Toast.LENGTH_LONG).show();
+ }
+
private void configureNotificationChannel() {
NotificationChannel channel = new NotificationChannel(
SelfManagedConnection.INCOMING_CALL_CHANNEL_ID, "Incoming Calls",
diff --git a/tests/src/com/android/server/telecom/tests/CallTest.java b/tests/src/com/android/server/telecom/tests/CallTest.java
index 541d278..d326a29 100644
--- a/tests/src/com/android/server/telecom/tests/CallTest.java
+++ b/tests/src/com/android/server/telecom/tests/CallTest.java
@@ -19,13 +19,17 @@
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.timeout;
import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyNoMoreInteractions;
+import static org.mockito.Mockito.verifyZeroInteractions;
import android.content.ComponentName;
import android.net.Uri;
@@ -34,6 +38,7 @@
import android.telecom.PhoneAccount;
import android.telecom.PhoneAccountHandle;
import android.test.suitebuilder.annotation.SmallTest;
+import android.util.Log;
import android.widget.Toast;
import androidx.test.ext.junit.runners.AndroidJUnit4;
@@ -44,6 +49,8 @@
import com.android.server.telecom.CallsManager;
import com.android.server.telecom.ClockProxy;
import com.android.server.telecom.ConnectionServiceWrapper;
+import com.android.server.telecom.InCallController;
+import com.android.server.telecom.InCallController.InCallServiceInfo;
import com.android.server.telecom.PhoneAccountRegistrar;
import com.android.server.telecom.PhoneNumberUtilsAdapter;
import com.android.server.telecom.TelecomSystem;
@@ -54,17 +61,23 @@
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
+import org.mockito.Mockito;
@RunWith(AndroidJUnit4.class)
public class CallTest extends TelecomTestCase {
private static final Uri TEST_ADDRESS = Uri.parse("tel:555-1212");
+ private static final ComponentName COMPONENT_NAME_1 = ComponentName
+ .unflattenFromString("com.foo/.Blah");
+ private static final ComponentName COMPONENT_NAME_2 = ComponentName
+ .unflattenFromString("com.bar/.Blah");
private static final PhoneAccountHandle SIM_1_HANDLE = new PhoneAccountHandle(
- ComponentName.unflattenFromString("com.foo/.Blah"), "Sim1");
+ COMPONENT_NAME_1, "Sim1");
private static final PhoneAccount SIM_1_ACCOUNT = new PhoneAccount.Builder(SIM_1_HANDLE, "Sim1")
.setCapabilities(PhoneAccount.CAPABILITY_SIM_SUBSCRIPTION
| PhoneAccount.CAPABILITY_CALL_PROVIDER)
.setIsEnabled(true)
.build();
+ private static final long TIMEOUT_MILLIS = 1000;
@Mock private CallsManager mMockCallsManager;
@Mock private CallerInfoLookupHelper mMockCallerInfoLookupHelper;
diff --git a/tests/src/com/android/server/telecom/tests/ConnectionServiceFixture.java b/tests/src/com/android/server/telecom/tests/ConnectionServiceFixture.java
index 26f24ef..5b4e800 100755
--- a/tests/src/com/android/server/telecom/tests/ConnectionServiceFixture.java
+++ b/tests/src/com/android/server/telecom/tests/ConnectionServiceFixture.java
@@ -342,6 +342,14 @@
throws RemoteException { }
@Override
+ public void onUsingAlternativeUi(String activeCallId, boolean usingAlternativeUi,
+ Session.Info info) throws RemoteException { }
+
+ @Override
+ public void onTrackedByNonUiService(String activeCallId, boolean isTracked,
+ Session.Info info) throws RemoteException { }
+
+ @Override
public void playDtmfTone(String callId, char digit,
Session.Info info) throws RemoteException { }
diff --git a/tests/src/com/android/server/telecom/tests/InCallControllerTests.java b/tests/src/com/android/server/telecom/tests/InCallControllerTests.java
index df11198..0b926fe 100644
--- a/tests/src/com/android/server/telecom/tests/InCallControllerTests.java
+++ b/tests/src/com/android/server/telecom/tests/InCallControllerTests.java
@@ -1190,6 +1190,7 @@
anyInt(), eq(UserHandle.CURRENT))).thenReturn(true);
when(mMockCall.isExternalCall()).thenReturn(isExternalCall);
when(mMockCall.isSelfManaged()).thenReturn(isSelfManagedCall);
+ when(mMockCall.visibleToInCallService()).thenReturn(isSelfManagedCall);
}
private ResolveInfo getDefResolveInfo(final boolean includeExternalCalls,