Loading src/com/android/server/telecom/InCallController.java +22 −28 Original line number Diff line number Diff line Loading @@ -21,6 +21,7 @@ import static android.os.Process.myUid; import android.Manifest; import android.annotation.NonNull; import android.annotation.Nullable; import android.app.AppOpsManager; import android.app.compat.CompatChanges; import android.app.Notification; Loading Loading @@ -90,17 +91,6 @@ public class InCallController extends CallsManagerListenerBase implements AppOpsManager.OnOpActiveChangedListener { public static final String NOTIFICATION_TAG = InCallController.class.getSimpleName(); public static final int IN_CALL_SERVICE_NOTIFICATION_ID = 3; /** * Enable a crash notification if the default dialer app does not implement the * {@link InCallService} and the system Dialer takes over. * * @hide */ @ChangeId @EnabledSince(targetSdkVersion = Build.VERSION_CODES.TIRAMISU) public static final long ENABLE_NOTIFICATION_FOR_DEFAULT_DIALER_CRASH = 218903401L; // bug id public class InCallServiceConnection { /** * Indicates that a call to {@link #connect(Call)} has succeeded and resulted in a Loading Loading @@ -1622,27 +1612,31 @@ public class InCallController extends CallsManagerListenerBase implements mNonUIInCallServiceConnections.connect(call); } private InCallServiceInfo getDefaultDialerComponent() { String packageName = mDefaultDialerCache.getDefaultDialerApplication( private @Nullable InCallServiceInfo getDefaultDialerComponent() { String defaultPhoneAppName = mDefaultDialerCache.getDefaultDialerApplication( mCallsManager.getCurrentUserHandle().getIdentifier()); String systemPackageName = mDefaultDialerCache.getSystemDialerApplication(); Log.d(this, "Default Dialer package: " + packageName); InCallServiceInfo defaultDialerComponent = (systemPackageName != null && systemPackageName.equals(packageName)) ? getInCallServiceComponent(packageName, IN_CALL_SERVICE_TYPE_SYSTEM_UI, true /* ignoreDisabled */) : getInCallServiceComponent(packageName, String systemPhoneAppName = mDefaultDialerCache.getSystemDialerApplication(); Log.d(this, "getDefaultDialerComponent: defaultPhoneAppName=[%s]", defaultPhoneAppName); Log.d(this, "getDefaultDialerComponent: systemPhoneAppName=[%s]", systemPhoneAppName); // Get the defaultPhoneApp InCallService component... InCallServiceInfo defaultPhoneAppComponent = (systemPhoneAppName != null && systemPhoneAppName.equals(defaultPhoneAppName)) ? /* The defaultPhoneApp is also the systemPhoneApp. Get systemPhoneApp info*/ getInCallServiceComponent(defaultPhoneAppName, IN_CALL_SERVICE_TYPE_SYSTEM_UI, true /* ignoreDisabled */) /* The defaultPhoneApp is NOT the systemPhoneApp. Get defaultPhoneApp info*/ : getInCallServiceComponent(defaultPhoneAppName, IN_CALL_SERVICE_TYPE_DEFAULT_DIALER_UI, true /* ignoreDisabled */); if (packageName != null && defaultDialerComponent == null && CompatChanges.isChangeEnabled(ENABLE_NOTIFICATION_FOR_DEFAULT_DIALER_CRASH, Binder.getCallingUid())) { // The in call service of default phone app is disabled, send notification. sendCrashedInCallServiceNotification(packageName); } Log.d(this, "getDefaultDialerComponent: defaultPhoneAppComponent=[%s]", defaultPhoneAppComponent); // defaultPhoneAppComponent is null in the case when the defaultPhoneApp does not implement // the InCallService && is the package is different from the systemPhoneApp return defaultDialerComponent; return defaultPhoneAppComponent; } private InCallServiceInfo getCurrentCarModeComponent() { Loading tests/src/com/android/server/telecom/tests/InCallControllerTests.java +2 −68 Original line number Diff line number Diff line Loading @@ -65,6 +65,7 @@ import android.content.pm.ResolveInfo; import android.content.pm.ServiceInfo; import android.content.res.Resources; import android.compat.testing.PlatformCompatChangeRule; import android.os.Binder; import android.os.Build; import android.os.Bundle; import android.os.Handler; Loading Loading @@ -917,13 +918,10 @@ public class InCallControllerTests extends TelecomTestCase { /** * Ensures that the {@link InCallController} will bind to an {@link InCallService} which * supports third party app. Also, we want to verify a notification is sent to apps targeting * Tiramisu and above when the InCallService of the default app is disabled. * supports third party app. */ @MediumTest @Test @CoreCompatChangeRule.EnableCompatChanges({ InCallController.ENABLE_NOTIFICATION_FOR_DEFAULT_DIALER_CRASH}) public void testBindToService_ThirdPartyApp() throws Exception { final MockitoSession mockitoSession = ExtendedMockito.mockitoSession() .strictness(Strictness.WARN) Loading Loading @@ -967,9 +965,6 @@ public class InCallControllerTests extends TelecomTestCase { // Should have next bound to the third party app op non ui app. verifyBinding(bindIntentCaptor, 1, APPOP_NONUI_PKG, APPOP_NONUI_CLASS); // Verify notification is sent by NotificationManager verify(mNotificationManager, times(1)).notify(eq(InCallController.NOTIFICATION_TAG), eq(InCallController.IN_CALL_SERVICE_NOTIFICATION_ID), any()); } finally { mockitoSession.finishMocking(); } Loading Loading @@ -1017,67 +1012,6 @@ public class InCallControllerTests extends TelecomTestCase { eq(InCallController.IN_CALL_SERVICE_NOTIFICATION_ID), any()); } /** * Ensures that the {@link InCallController} will bind to an {@link InCallService} which * supports third party app. Also, we want to verify a notification is NOT sent to apps * targeting below Tiramisu when the InCallService of the default app is disabled. */ @MediumTest @Test @CoreCompatChangeRule.DisableCompatChanges({ InCallController.ENABLE_NOTIFICATION_FOR_DEFAULT_DIALER_CRASH}) public void testBindToService_ThirdPartyAppBelowTiramisu() throws Exception { final MockitoSession mockitoSession = ExtendedMockito.mockitoSession() .strictness(Strictness.WARN) .spyStatic(PermissionChecker.class) .startMocking(); try { setupMocks(false /* isExternalCall */); setupMockPackageManager(false /* default */, false /* nonui */, true /* appop_nonui */, true /* system */, false /* external calls */, false /* self mgd in default */, false /* self mgd in car*/); ApplicationInfo applicationInfo = new ApplicationInfo(); applicationInfo.targetSdkVersion = Build.VERSION_CODES.S_V2; // set up mock call for ICSC#sendCrashedInCallServiceNotification(String) when(mMockContext.getApplicationInfo()).thenReturn(applicationInfo); // Enable Third Party Companion App ExtendedMockito.doReturn(PermissionChecker.PERMISSION_GRANTED).when(() -> PermissionChecker.checkPermissionForDataDeliveryFromDataSource( any(Context.class), eq(Manifest.permission.MANAGE_ONGOING_CALLS), anyInt(), any(AttributionSource.class), nullable(String.class))); // Now bind; we should bind to the system dialer and app op non ui app. mInCallController.bindToServices(mMockCall); // Bind InCallServices ArgumentCaptor<Intent> bindIntentCaptor = ArgumentCaptor.forClass(Intent.class); verify(mMockContext, times(2)).bindServiceAsUser( bindIntentCaptor.capture(), any(ServiceConnection.class), eq(Context.BIND_AUTO_CREATE | Context.BIND_FOREGROUND_SERVICE | Context.BIND_ALLOW_BACKGROUND_ACTIVITY_STARTS), eq(UserHandle.CURRENT)); // Verify bind assertEquals(2, bindIntentCaptor.getAllValues().size()); // Should have first bound to the system dialer. verifyBinding(bindIntentCaptor, 0, SYS_PKG, SYS_CLASS); // Should have next bound to the third party app op non ui app. verifyBinding(bindIntentCaptor, 1, APPOP_NONUI_PKG, APPOP_NONUI_CLASS); // Verify notification is NOT sent by NotificationManager verify(mNotificationManager, times(0)).notify(eq(InCallController.NOTIFICATION_TAG), eq(InCallController.IN_CALL_SERVICE_NOTIFICATION_ID), any()); } finally { mockitoSession.finishMocking(); } } @MediumTest @Test public void testSanitizeContactName() throws Exception { Loading Loading
src/com/android/server/telecom/InCallController.java +22 −28 Original line number Diff line number Diff line Loading @@ -21,6 +21,7 @@ import static android.os.Process.myUid; import android.Manifest; import android.annotation.NonNull; import android.annotation.Nullable; import android.app.AppOpsManager; import android.app.compat.CompatChanges; import android.app.Notification; Loading Loading @@ -90,17 +91,6 @@ public class InCallController extends CallsManagerListenerBase implements AppOpsManager.OnOpActiveChangedListener { public static final String NOTIFICATION_TAG = InCallController.class.getSimpleName(); public static final int IN_CALL_SERVICE_NOTIFICATION_ID = 3; /** * Enable a crash notification if the default dialer app does not implement the * {@link InCallService} and the system Dialer takes over. * * @hide */ @ChangeId @EnabledSince(targetSdkVersion = Build.VERSION_CODES.TIRAMISU) public static final long ENABLE_NOTIFICATION_FOR_DEFAULT_DIALER_CRASH = 218903401L; // bug id public class InCallServiceConnection { /** * Indicates that a call to {@link #connect(Call)} has succeeded and resulted in a Loading Loading @@ -1622,27 +1612,31 @@ public class InCallController extends CallsManagerListenerBase implements mNonUIInCallServiceConnections.connect(call); } private InCallServiceInfo getDefaultDialerComponent() { String packageName = mDefaultDialerCache.getDefaultDialerApplication( private @Nullable InCallServiceInfo getDefaultDialerComponent() { String defaultPhoneAppName = mDefaultDialerCache.getDefaultDialerApplication( mCallsManager.getCurrentUserHandle().getIdentifier()); String systemPackageName = mDefaultDialerCache.getSystemDialerApplication(); Log.d(this, "Default Dialer package: " + packageName); InCallServiceInfo defaultDialerComponent = (systemPackageName != null && systemPackageName.equals(packageName)) ? getInCallServiceComponent(packageName, IN_CALL_SERVICE_TYPE_SYSTEM_UI, true /* ignoreDisabled */) : getInCallServiceComponent(packageName, String systemPhoneAppName = mDefaultDialerCache.getSystemDialerApplication(); Log.d(this, "getDefaultDialerComponent: defaultPhoneAppName=[%s]", defaultPhoneAppName); Log.d(this, "getDefaultDialerComponent: systemPhoneAppName=[%s]", systemPhoneAppName); // Get the defaultPhoneApp InCallService component... InCallServiceInfo defaultPhoneAppComponent = (systemPhoneAppName != null && systemPhoneAppName.equals(defaultPhoneAppName)) ? /* The defaultPhoneApp is also the systemPhoneApp. Get systemPhoneApp info*/ getInCallServiceComponent(defaultPhoneAppName, IN_CALL_SERVICE_TYPE_SYSTEM_UI, true /* ignoreDisabled */) /* The defaultPhoneApp is NOT the systemPhoneApp. Get defaultPhoneApp info*/ : getInCallServiceComponent(defaultPhoneAppName, IN_CALL_SERVICE_TYPE_DEFAULT_DIALER_UI, true /* ignoreDisabled */); if (packageName != null && defaultDialerComponent == null && CompatChanges.isChangeEnabled(ENABLE_NOTIFICATION_FOR_DEFAULT_DIALER_CRASH, Binder.getCallingUid())) { // The in call service of default phone app is disabled, send notification. sendCrashedInCallServiceNotification(packageName); } Log.d(this, "getDefaultDialerComponent: defaultPhoneAppComponent=[%s]", defaultPhoneAppComponent); // defaultPhoneAppComponent is null in the case when the defaultPhoneApp does not implement // the InCallService && is the package is different from the systemPhoneApp return defaultDialerComponent; return defaultPhoneAppComponent; } private InCallServiceInfo getCurrentCarModeComponent() { Loading
tests/src/com/android/server/telecom/tests/InCallControllerTests.java +2 −68 Original line number Diff line number Diff line Loading @@ -65,6 +65,7 @@ import android.content.pm.ResolveInfo; import android.content.pm.ServiceInfo; import android.content.res.Resources; import android.compat.testing.PlatformCompatChangeRule; import android.os.Binder; import android.os.Build; import android.os.Bundle; import android.os.Handler; Loading Loading @@ -917,13 +918,10 @@ public class InCallControllerTests extends TelecomTestCase { /** * Ensures that the {@link InCallController} will bind to an {@link InCallService} which * supports third party app. Also, we want to verify a notification is sent to apps targeting * Tiramisu and above when the InCallService of the default app is disabled. * supports third party app. */ @MediumTest @Test @CoreCompatChangeRule.EnableCompatChanges({ InCallController.ENABLE_NOTIFICATION_FOR_DEFAULT_DIALER_CRASH}) public void testBindToService_ThirdPartyApp() throws Exception { final MockitoSession mockitoSession = ExtendedMockito.mockitoSession() .strictness(Strictness.WARN) Loading Loading @@ -967,9 +965,6 @@ public class InCallControllerTests extends TelecomTestCase { // Should have next bound to the third party app op non ui app. verifyBinding(bindIntentCaptor, 1, APPOP_NONUI_PKG, APPOP_NONUI_CLASS); // Verify notification is sent by NotificationManager verify(mNotificationManager, times(1)).notify(eq(InCallController.NOTIFICATION_TAG), eq(InCallController.IN_CALL_SERVICE_NOTIFICATION_ID), any()); } finally { mockitoSession.finishMocking(); } Loading Loading @@ -1017,67 +1012,6 @@ public class InCallControllerTests extends TelecomTestCase { eq(InCallController.IN_CALL_SERVICE_NOTIFICATION_ID), any()); } /** * Ensures that the {@link InCallController} will bind to an {@link InCallService} which * supports third party app. Also, we want to verify a notification is NOT sent to apps * targeting below Tiramisu when the InCallService of the default app is disabled. */ @MediumTest @Test @CoreCompatChangeRule.DisableCompatChanges({ InCallController.ENABLE_NOTIFICATION_FOR_DEFAULT_DIALER_CRASH}) public void testBindToService_ThirdPartyAppBelowTiramisu() throws Exception { final MockitoSession mockitoSession = ExtendedMockito.mockitoSession() .strictness(Strictness.WARN) .spyStatic(PermissionChecker.class) .startMocking(); try { setupMocks(false /* isExternalCall */); setupMockPackageManager(false /* default */, false /* nonui */, true /* appop_nonui */, true /* system */, false /* external calls */, false /* self mgd in default */, false /* self mgd in car*/); ApplicationInfo applicationInfo = new ApplicationInfo(); applicationInfo.targetSdkVersion = Build.VERSION_CODES.S_V2; // set up mock call for ICSC#sendCrashedInCallServiceNotification(String) when(mMockContext.getApplicationInfo()).thenReturn(applicationInfo); // Enable Third Party Companion App ExtendedMockito.doReturn(PermissionChecker.PERMISSION_GRANTED).when(() -> PermissionChecker.checkPermissionForDataDeliveryFromDataSource( any(Context.class), eq(Manifest.permission.MANAGE_ONGOING_CALLS), anyInt(), any(AttributionSource.class), nullable(String.class))); // Now bind; we should bind to the system dialer and app op non ui app. mInCallController.bindToServices(mMockCall); // Bind InCallServices ArgumentCaptor<Intent> bindIntentCaptor = ArgumentCaptor.forClass(Intent.class); verify(mMockContext, times(2)).bindServiceAsUser( bindIntentCaptor.capture(), any(ServiceConnection.class), eq(Context.BIND_AUTO_CREATE | Context.BIND_FOREGROUND_SERVICE | Context.BIND_ALLOW_BACKGROUND_ACTIVITY_STARTS), eq(UserHandle.CURRENT)); // Verify bind assertEquals(2, bindIntentCaptor.getAllValues().size()); // Should have first bound to the system dialer. verifyBinding(bindIntentCaptor, 0, SYS_PKG, SYS_CLASS); // Should have next bound to the third party app op non ui app. verifyBinding(bindIntentCaptor, 1, APPOP_NONUI_PKG, APPOP_NONUI_CLASS); // Verify notification is NOT sent by NotificationManager verify(mNotificationManager, times(0)).notify(eq(InCallController.NOTIFICATION_TAG), eq(InCallController.IN_CALL_SERVICE_NOTIFICATION_ID), any()); } finally { mockitoSession.finishMocking(); } } @MediumTest @Test public void testSanitizeContactName() throws Exception { Loading