Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 009ef191 authored by Thomas Stuart's avatar Thomas Stuart Committed by Automerger Merge Worker
Browse files

Merge "isInSelfManagedCall for (package,user) should return true for calls...

Merge "isInSelfManagedCall for (package,user) should return true for calls being setup" into udc-dev am: 6060f0ce

Original change: https://googleplex-android-review.googlesource.com/c/platform/packages/services/Telecomm/+/23697350



Change-Id: I2e7cbafddb54ef60697e6ee247f33d4f02109e43
Signed-off-by: default avatarAutomerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
parents da785655 6060f0ce
Loading
Loading
Loading
Loading
+46 −13
Original line number Diff line number Diff line
@@ -352,6 +352,16 @@ public class CallsManager extends Call.ListenerBase
    private final Set<Call> mCalls = Collections.newSetFromMap(
            new ConcurrentHashMap<Call, Boolean>(8, 0.9f, 1));

    /**
     * List of self-managed calls that have been initialized but not yet added to
     * CallsManager#addCall(Call). There is a window of time when a Call has been added to Telecom
     * (e.g. TelecomManager#addNewIncomingCall) to actually added in CallsManager#addCall(Call).
     * This list is helpful for the NotificationManagerService to know that Telecom is currently
     * setting up a call which is an important set in making notifications non-dismissible.
     */
    private final Set<Call> mSelfManagedCallsBeingSetup = Collections.newSetFromMap(
            new ConcurrentHashMap<Call, Boolean>(8, 0.9f, 1));

    /**
     * A pending call is one which requires user-intervention in order to be placed.
     * Used by {@link #startCallConfirmation}.
@@ -1398,6 +1408,8 @@ public class CallsManager extends Call.ListenerBase
            // Required for backwards compatibility
            handle = extras.getParcelable(TelephonyManager.EXTRA_INCOMING_NUMBER);
        }
        PhoneAccount phoneAccount = mPhoneAccountRegistrar.getPhoneAccountUnchecked(
                phoneAccountHandle);
        Call call = new Call(
                generateNextCallId(extras),
                mContext,
@@ -1414,6 +1426,15 @@ public class CallsManager extends Call.ListenerBase
                isConference, /* isConference */
                mClockProxy,
                mToastFactory);
        // Ensure new calls related to self-managed calls/connections are set as such. This will
        // be overridden when the actual connection is returned in startCreateConnection, however
        // doing this now ensures the logs and any other logic will treat this call as self-managed
        // from the moment it is created.
        boolean isSelfManaged = phoneAccount != null && phoneAccount.isSelfManaged();
        call.setIsSelfManaged(isSelfManaged);
        // It's important to start tracking self-managed calls as soon as the Call object is
        // initialized so NotificationManagerService is aware Telecom is setting up a call
        if (isSelfManaged) mSelfManagedCallsBeingSetup.add(call);

        // set properties for transactional call
        if (extras.containsKey(TelecomManager.TRANSACTION_CALL_ID_KEY)) {
@@ -1434,15 +1455,8 @@ public class CallsManager extends Call.ListenerBase
            call.setAssociatedUser(phoneAccountHandle.getUserHandle());
        }

        // Ensure new calls related to self-managed calls/connections are set as such. This will
        // be overridden when the actual connection is returned in startCreateConnection, however
        // doing this now ensures the logs and any other logic will treat this call as self-managed
        // from the moment it is created.
        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);
@@ -1745,7 +1759,7 @@ public class CallsManager extends Call.ListenerBase
                    isConference ? participants : null,
                    null /* gatewayInfo */,
                    null /* connectionManagerPhoneAccount */,
                    null /* requestedAccountHandle */,
                    requestedAccountHandle /* targetPhoneAccountHandle */,
                    Call.CALL_DIRECTION_OUTGOING /* callDirection */,
                    false /* forceAttachToExistingConnection */,
                    isConference, /* isConference */
@@ -1766,7 +1780,6 @@ public class CallsManager extends Call.ListenerBase
                                TelecomManager.PRESENTATION_ALLOWED);
                    }
                }
                call.setTargetPhoneAccount(requestedAccountHandle);
            }

            call.initAnalytics(callingPackage, creationLogs.toString());
@@ -1805,6 +1818,9 @@ public class CallsManager extends Call.ListenerBase
        } else {
            isReusedCall = true;
        }
        // It's important to start tracking self-managed calls as soon as the Call object is
        // initialized so NotificationManagerService is aware Telecom is setting up a call
        if (isSelfManaged) mSelfManagedCallsBeingSetup.add(call);

        int videoState = VideoProfile.STATE_AUDIO_ONLY;
        if (extras != null) {
@@ -4241,6 +4257,7 @@ public class CallsManager extends Call.ListenerBase
        Log.i(this, "addCall(%s)", call);
        call.addListener(this);
        mCalls.add(call);
        mSelfManagedCallsBeingSetup.remove(call);

        // Specifies the time telecom finished routing the call. This is used by the dialer for
        // analytics.
@@ -4284,6 +4301,7 @@ public class CallsManager extends Call.ListenerBase
            mCalls.remove(call);
            shouldNotify = true;
        }
        mSelfManagedCallsBeingSetup.remove(call);

        call.destroy();
        updateExternalCallCanPullSupport();
@@ -4541,8 +4559,10 @@ public class CallsManager extends Call.ListenerBase
     * @return {@code true} if the app has ongoing calls, or {@code false} otherwise.
     */
    public boolean isInSelfManagedCall(String packageName, UserHandle userHandle) {
        return mCalls.stream().anyMatch(
                c -> c.isSelfManaged()
        return mSelfManagedCallsBeingSetup.stream().anyMatch(c -> c.isSelfManaged()
                && c.getTargetPhoneAccount().getComponentName().getPackageName().equals(packageName)
                && c.getTargetPhoneAccount().getUserHandle().equals(userHandle)) ||
                mCalls.stream().anyMatch(c -> c.isSelfManaged()
                && c.getTargetPhoneAccount().getComponentName().getPackageName().equals(packageName)
                && c.getTargetPhoneAccount().getUserHandle().equals(userHandle));
    }
@@ -4734,11 +4754,14 @@ public class CallsManager extends Call.ListenerBase
    }

    /**
     * Determines if there are any self-managed calls.
     * Note: isInSelfManagedCall(packageName, UserHandle) should always be used in favor or this
     * method. This method determines if there are any self-managed calls globally.
     * @return {@code true} if there are self-managed calls, {@code false} otherwise.
     */
    @VisibleForTesting
    public boolean hasSelfManagedCalls() {
        return mCalls.stream().filter(call -> call.isSelfManaged()).count() > 0;
        return mSelfManagedCallsBeingSetup.size() > 0 ||
                mCalls.stream().filter(call -> call.isSelfManaged()).count() > 0;
    }

    /**
@@ -6493,4 +6516,14 @@ public class CallsManager extends Call.ListenerBase
        }
        call.getTransactionServiceWrapper().stopCallStreaming(call);
    }

    @VisibleForTesting
    public Set<Call> getSelfManagedCallsBeingSetup() {
        return mSelfManagedCallsBeingSetup;
    }

    @VisibleForTesting
    public void addCallBeingSetup(Call call) {
        mSelfManagedCallsBeingSetup.add(call);
    }
}
+3 −1
Original line number Diff line number Diff line
@@ -251,6 +251,7 @@ public class InCallActivity extends Activity {
                    @Override
                    public void onResult(CallControl callControl) {
                        Log.i(TAG, "addCall: onResult: callback fired");
                        Utils.postIncomingCallStyleNotification(getApplicationContext());
                        mVoipCall.onAddCallControl(callControl);
                        updateCallId();
                        updateCurrentEndpoint();
@@ -275,7 +276,8 @@ public class InCallActivity extends Activity {
        mAudioRecord.stop();
        try {
            mAudioRecord.unregisterAudioRecordingCallback(mAudioRecordingCallback);
        } catch (IllegalArgumentException e) {
            Utils.clearNotification(getApplicationContext());
        } catch (Exception e) {
            // pass through
        }
    }
+14 −0
Original line number Diff line number Diff line
@@ -77,11 +77,16 @@ public class Utils {
                        pendingAnswer, pendingReject)
                )
                .setFullScreenIntent(pendingAnswer, true)
                .setOngoing(true)
                .build();

        return callStyleNotification;
    }

    public static void postIncomingCallStyleNotification(Context context) {
        NotificationManager nm = context.getSystemService(NotificationManager.class);
        nm.notify(Utils.CALL_NOTIFICATION_ID, createCallStyleNotification(context));
    }

    public static void updateCallStyleNotification_toOngoingCall(Context context) {
        PendingIntent ongoingCall = PendingIntent.getActivity(context, 0,
@@ -97,6 +102,7 @@ public class Utils {
                        ongoingCall)
                )
                .setFullScreenIntent(ongoingCall, true)
                .setOngoing(true)
                .build();

        NotificationManager notificationManager =
@@ -105,6 +111,14 @@ public class Utils {
        notificationManager.notify(CALL_NOTIFICATION_ID, callStyleNotification);
    }

    public static void clearNotification(Context context) {
        NotificationManager notificationManager =
                context.getSystemService(NotificationManager.class);
        if (notificationManager != null) {
            notificationManager.cancel(CALL_NOTIFICATION_ID);
        }
    }

    public static MediaPlayer createMediaPlayer(Context context) {
        int audioToPlay = (Math.random() > 0.5f) ?
                com.android.server.telecom.transactionalVoipApp.R.raw.sample_audio :
+1 −2
Original line number Diff line number Diff line
@@ -99,8 +99,6 @@ public class VoipAppMainActivity extends Activity {
    }

    private void startInCallActivity(int direction) {
        mNotificationManager.notify(Utils.CALL_NOTIFICATION_ID,
                Utils.createCallStyleNotification(getApplicationContext()));
        Bundle extras = new Bundle();
        extras.putInt(Utils.sCALL_DIRECTION_KEY, direction);
        Intent intent = new Intent(getApplicationContext(), InCallActivity.class);
@@ -142,6 +140,7 @@ public class VoipAppMainActivity extends Activity {
    protected void onDestroy() {
        Log.i(TAG, ACT_STATE_TAG + " onDestroy: is called before the activity is"
                + " destroyed. ");
        Utils.clearNotification(getApplicationContext());
        super.onDestroy();
    }
}
+112 −1
Original line number Diff line number Diff line
@@ -62,7 +62,6 @@ import android.os.SystemClock;
import android.os.UserHandle;
import android.os.UserManager;
import android.provider.BlockedNumberContract;
import android.provider.Telephony;
import android.telecom.CallException;
import android.telecom.CallScreeningService;
import android.telecom.CallerInfo;
@@ -156,6 +155,8 @@ public class CallsManagerTest extends TelecomTestCase {
    private static final int TEST_TIMEOUT = 5000;  // milliseconds
    private static final long STATE_TIMEOUT = 5000L;
    private static final int SECONDARY_USER_ID = 12;
    private static final UserHandle TEST_USER_HANDLE = UserHandle.of(123);
    private static final String TEST_PACKAGE_NAME = "GoogleMeet";
    private static final PhoneAccountHandle SIM_1_HANDLE = new PhoneAccountHandle(
            ComponentName.unflattenFromString("com.foo/.Blah"), "Sim1");
    private static final PhoneAccountHandle SIM_1_HANDLE_SECONDARY = new PhoneAccountHandle(
@@ -173,6 +174,8 @@ public class CallsManagerTest extends TelecomTestCase {
            ComponentName.unflattenFromString("com.baz/.Self"), "Self");
    private static final PhoneAccountHandle SELF_MANAGED_2_HANDLE = new PhoneAccountHandle(
            ComponentName.unflattenFromString("com.baz/.Self2"), "Self2");
    private static final PhoneAccountHandle SELF_MANAGED_W_CUSTOM_HANDLE = new PhoneAccountHandle(
            new ComponentName(TEST_PACKAGE_NAME, "class"), "1", TEST_USER_HANDLE);
    private static final PhoneAccount SIM_1_ACCOUNT = new PhoneAccount.Builder(SIM_1_HANDLE, "Sim1")
            .setCapabilities(PhoneAccount.CAPABILITY_SIM_SUBSCRIPTION
                    | PhoneAccount.CAPABILITY_CALL_PROVIDER
@@ -202,6 +205,11 @@ public class CallsManagerTest extends TelecomTestCase {
            .setCapabilities(PhoneAccount.CAPABILITY_SELF_MANAGED)
            .setIsEnabled(true)
            .build();
    private static final PhoneAccount SM_W_DIFFERENT_PACKAGE_AND_USER = new PhoneAccount.Builder(
            SELF_MANAGED_W_CUSTOM_HANDLE, "Self")
            .setCapabilities(PhoneAccount.CAPABILITY_SELF_MANAGED)
            .setIsEnabled(true)
            .build();
    private static final Uri TEST_ADDRESS = Uri.parse("tel:555-1212");
    private static final Uri TEST_ADDRESS2 = Uri.parse("tel:555-1213");
    private static final Uri TEST_ADDRESS3 = Uri.parse("tel:555-1214");
@@ -3078,6 +3086,109 @@ public class CallsManagerTest extends TelecomTestCase {
                eq(false));
    }

    /**
     * Verify CallsManager#isInSelfManagedCall(packageName, userHandle) returns true when
     * CallsManager is first made aware of the incoming call in processIncomingCallIntent.
     */
    @SmallTest
    @Test
    public void testAddNewIncomingCall_IsInSelfManagedCall() {
        // GIVEN
        assertEquals(0, mCallsManager.getSelfManagedCallsBeingSetup().size());
        assertFalse(mCallsManager.isInSelfManagedCall(TEST_PACKAGE_NAME, TEST_USER_HANDLE));

        // WHEN
        when(mPhoneAccountRegistrar.getPhoneAccountUnchecked(any()))
                .thenReturn(SM_W_DIFFERENT_PACKAGE_AND_USER);

        // THEN
        mCallsManager.processIncomingCallIntent(SELF_MANAGED_W_CUSTOM_HANDLE, new Bundle(), false);

        assertEquals(1, mCallsManager.getSelfManagedCallsBeingSetup().size());
        assertTrue(mCallsManager.isInSelfManagedCall(TEST_PACKAGE_NAME, TEST_USER_HANDLE));
        assertEquals(0, mCallsManager.getCalls().size());
    }

    /**
     * Verify CallsManager#isInSelfManagedCall(packageName, userHandle) returns true when
     * CallsManager is first made aware of the outgoing call in StartOutgoingCall.
     */
    @SmallTest
    @Test
    public void testStartOutgoing_IsInSelfManagedCall() {
        // GIVEN
        assertEquals(0, mCallsManager.getSelfManagedCallsBeingSetup().size());
        assertFalse(mCallsManager.isInSelfManagedCall(TEST_PACKAGE_NAME, TEST_USER_HANDLE));

        // WHEN
        when(mPhoneAccountRegistrar.getPhoneAccount(any(), any()))
                .thenReturn(SM_W_DIFFERENT_PACKAGE_AND_USER);
        // Ensure contact info lookup succeeds
        doAnswer(invocation -> {
            Uri handle = invocation.getArgument(0);
            CallerInfo info = new CallerInfo();
            CompletableFuture<Pair<Uri, CallerInfo>> callerInfoFuture = new CompletableFuture<>();
            callerInfoFuture.complete(new Pair<>(handle, info));
            return callerInfoFuture;
        }).when(mCallerInfoLookupHelper).startLookup(any(Uri.class));
        // Ensure we have candidate phone account handle info.
        when(mPhoneAccountRegistrar.getOutgoingPhoneAccountForScheme(any(), any())).thenReturn(
                SELF_MANAGED_W_CUSTOM_HANDLE);
        when(mPhoneAccountRegistrar.getCallCapablePhoneAccounts(any(), anyBoolean(),
                any(), anyInt(), anyInt(), anyBoolean())).thenReturn(
                new ArrayList<>(List.of(SELF_MANAGED_W_CUSTOM_HANDLE)));

        // THEN
        mCallsManager.startOutgoingCall(TEST_ADDRESS, SELF_MANAGED_W_CUSTOM_HANDLE, new Bundle(),
                TEST_USER_HANDLE, new Intent(), TEST_PACKAGE_NAME);

        assertEquals(1, mCallsManager.getSelfManagedCallsBeingSetup().size());
        assertTrue(mCallsManager.isInSelfManagedCall(TEST_PACKAGE_NAME, TEST_USER_HANDLE));
        assertEquals(0, mCallsManager.getCalls().size());
    }

    /**
     * Verify SelfManagedCallsBeingSetup is being cleaned up in CallsManager#addCall and
     * CallsManager#removeCall.  This ensures no memory leaks.
     */
    @SmallTest
    @Test
    public void testCallsBeingSetupCleanup() {
        Call spyCall = addSpyCall();
        assertEquals(0, mCallsManager.getSelfManagedCallsBeingSetup().size());
        // verify CallsManager#removeCall removes the call from SelfManagedCallsBeingSetup
        mCallsManager.addCallBeingSetup(spyCall);
        mCallsManager.removeCall(spyCall);
        assertEquals(0, mCallsManager.getSelfManagedCallsBeingSetup().size());
        // verify CallsManager#addCall removes the call from SelfManagedCallsBeingSetup
        mCallsManager.addCallBeingSetup(spyCall);
        mCallsManager.addCall(spyCall);
        assertEquals(0, mCallsManager.getSelfManagedCallsBeingSetup().size());
    }

    /**
     * Verify isInSelfManagedCall returns false if there is a self-managed call, but it is for a
     * different package and user
     */
    @SmallTest
    @Test
    public void testIsInSelfManagedCall_PackageUserQueryIsWorkingAsIntended() {
        // start an active call
        Call randomCall = createSpyCall(SELF_MANAGED_HANDLE, CallState.ACTIVE);
        mCallsManager.addCallBeingSetup(randomCall);
        assertEquals(1, mCallsManager.getSelfManagedCallsBeingSetup().size());
        // query isInSelfManagedCall for a package that is NOT in a call;  expect false
        assertFalse(mCallsManager.isInSelfManagedCall(TEST_PACKAGE_NAME, TEST_USER_HANDLE));
        // start another call
        Call targetCall = addSpyCall(SELF_MANAGED_W_CUSTOM_HANDLE, CallState.DIALING);
        when(targetCall.getTargetPhoneAccount()).thenReturn(SELF_MANAGED_W_CUSTOM_HANDLE);
        when(targetCall.isSelfManaged()).thenReturn(true);
        mCallsManager.addCallBeingSetup(targetCall);
        // query isInSelfManagedCall for a package that is in a call
        assertTrue(mCallsManager.isInSelfManagedCall(TEST_PACKAGE_NAME, TEST_USER_HANDLE));
    }


    private Call addSpyCall() {
        return addSpyCall(SIM_2_HANDLE, CallState.ACTIVE);
    }