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

Commit 87df4bcf authored by Pranav Madapurmath's avatar Pranav Madapurmath Committed by Android (Google) Code Review
Browse files

Merge "DSDA: Deflect MMI codes" into main

parents 1ac2e832 aba2f0ae
Loading
Loading
Loading
Loading
+3 −0
Original line number Diff line number Diff line
@@ -423,4 +423,7 @@
    <!-- In-call screen: error message shown when the user attempts to place a call, but the live
         call cannot be held. -->
    <string name="callFailed_unholdable_call">Cannot place a call as there is an unholdable call. Disconnect the call prior to placing a new call.</string>
    <!-- In-call screen: error message shown when the user attempts to dial an MMI code, but there
         is an ongoing call on a different phone account. -->
    <string name="callFailed_reject_mmi">This MMI code is not available for calls across multiple accounts.</string>
</resources>
+40 −13
Original line number Diff line number Diff line
@@ -278,7 +278,7 @@ public class CallsManager extends Call.ListenerBase
     * {@link #getNumCallsWithState(int, Call, PhoneAccountHandle, int...)} to indicate both managed
     * and self-managed calls should be included.
     */
    private static final int CALL_FILTER_ALL = 3;
    public static final int CALL_FILTER_ALL = 3;

    private static final String PERMISSION_PROCESS_PHONE_ACCOUNT_REGISTRATION =
            "android.permission.PROCESS_PHONE_ACCOUNT_REGISTRATION";
@@ -796,7 +796,7 @@ public class CallsManager extends Call.ListenerBase
        mBlockedNumbersManager = mFeatureFlags.telecomMainlineBlockedNumbersManager()
                ? mContext.getSystemService(BlockedNumbersManager.class)
                : null;
        mCallSequencingAdapter = new CallsManagerCallSequencingAdapter(this,
        mCallSequencingAdapter = new CallsManagerCallSequencingAdapter(this, mContext,
                new CallSequencingController(this, mContext, mClockProxy,
                        mAnomalyReporter, mTimeoutsAdapter, mMetricsController,
                        mFeatureFlags), mCallAudioManager, mFeatureFlags);
@@ -2187,7 +2187,15 @@ public class CallsManager extends Call.ListenerBase
                potentialPhoneAccounts -> {
                    Log.i(CallsManager.this, "make room for outgoing call stage");
                    if (mMmiUtils.isPotentialInCallMMICode(handle) && !isSelfManaged) {
                        boolean shouldAllowMmiCode = mCallSequencingAdapter
                                .shouldAllowMmiCode(finalCall);
                        if (shouldAllowMmiCode) {
                            return CompletableFuture.completedFuture(true);
                        } else {
                            Log.i(this, "Rejecting the MMI code because there is an "
                                    + "ongoing call on a different phone account.");
                            return CompletableFuture.completedFuture(false);
                        }
                    }
                    // If a call is being reused, then it has already passed the
                    // makeRoomForOutgoingCall check once and will fail the second time due to the
@@ -5095,14 +5103,40 @@ public class CallsManager extends Call.ListenerBase
     *                   ({@link #CALL_FILTER_ALL}).
     * @param excludeCall Where {@code non-null}, this call is excluded from the count.
     * @param phoneAccountHandle Where {@code non-null}, calls for this {@link PhoneAccountHandle}
     *                           are excluded from the count.
     *                           are included in the count.
     * @param states The list of {@link CallState}s to include in the count.
     * @return Count of calls matching criteria.
     */
    @VisibleForTesting
    public int getNumCallsWithState(final int callFilter, Call excludeCall,
                                    PhoneAccountHandle phoneAccountHandle, int... states) {
        Stream<Call> callsStream = getCallsWithState(callFilter, excludeCall, states);

        // If a phone account handle was specified, only consider calls for that phone account.
        if (phoneAccountHandle != null) {
            callsStream = callsStream.filter(
                    call -> phoneAccountHandle.equals(call.getTargetPhoneAccount()));
        }

        return (int) callsStream.count();
    }

    @VisibleForTesting
    public int getNumCallsWithStateWithoutHandle(final int callFilter, Call excludeCall,
            PhoneAccountHandle phoneAccountHandle, int... states) {
        Stream<Call> callsStream = getCallsWithState(callFilter, excludeCall, states);

        // If a phone account handle was specified, only consider calls not associated with that
        // phone account.
        if (phoneAccountHandle != null) {
            callsStream = callsStream.filter(
                    call -> !phoneAccountHandle.equals(call.getTargetPhoneAccount()));
        }

        return (int) callsStream.count();
    }

    private Stream<Call> getCallsWithState(final int callFilter, Call excludeCall, int... states) {
        Set<Integer> desiredStates = IntStream.of(states).boxed().collect(Collectors.toSet());

        Stream<Call> callsStream = mCalls.stream()
@@ -5120,15 +5154,8 @@ public class CallsManager extends Call.ListenerBase
            callsStream = callsStream.filter(call -> call != excludeCall);
        }

        // If a phone account handle was specified, only consider calls for that phone account.
        if (phoneAccountHandle != null) {
            callsStream = callsStream.filter(
                    call -> phoneAccountHandle.equals(call.getTargetPhoneAccount()));
        return callsStream;
    }

        return (int) callsStream.count();
    }

    /**
     * Determines the number of calls (visible to the calling user) matching the specified criteria.
     * This is an overloaded method which is being used in a security patch to fix up the call
@@ -5145,7 +5172,7 @@ public class CallsManager extends Call.ListenerBase
     *                    {@link UserHandle}.
     * @param hasCrossUserAccess indicates if calling user has the INTERACT_ACROSS_USERS permission.
     * @param phoneAccountHandle Where {@code non-null}, calls for this {@link PhoneAccountHandle}
     *                           are excluded from the count.
     *                           are included in the count.
     * @param states The list of {@link CallState}s to include in the count.
     * @return Count of calls matching criteria.
     */
+14 −0
Original line number Diff line number Diff line
@@ -18,10 +18,12 @@ package com.android.server.telecom.callsequencing;

import static android.Manifest.permission.CALL_PRIVILEGED;

import static com.android.server.telecom.CallsManager.CALL_FILTER_ALL;
import static com.android.server.telecom.CallsManager.LIVE_CALL_STUCK_CONNECTING_EMERGENCY_ERROR_MSG;
import static com.android.server.telecom.CallsManager.LIVE_CALL_STUCK_CONNECTING_EMERGENCY_ERROR_UUID;
import static com.android.server.telecom.CallsManager.LIVE_CALL_STUCK_CONNECTING_ERROR_MSG;
import static com.android.server.telecom.CallsManager.LIVE_CALL_STUCK_CONNECTING_ERROR_UUID;
import static com.android.server.telecom.CallsManager.ONGOING_CALL_STATES;
import static com.android.server.telecom.CallsManager.OUTGOING_CALL_STATES;
import static com.android.server.telecom.UserUtil.showErrorDialogForRestrictedOutgoingCall;

@@ -906,6 +908,18 @@ public class CallSequencingController {
        }, new LoggedHandlerExecutor(mHandler, sessionName, mCallsManager.getLock()));
    }

    public boolean hasMmiCodeRestriction(Call call) {
        if (mCallsManager.getNumCallsWithStateWithoutHandle(
                CALL_FILTER_ALL, call, call.getTargetPhoneAccount(), ONGOING_CALL_STATES) > 0) {
            // Set disconnect cause so that error will be printed out when call is disconnected.
            CharSequence msg = mContext.getText(R.string.callFailed_reject_mmi);
            call.setOverrideDisconnectCauseCode(new DisconnectCause(DisconnectCause.ERROR, msg, msg,
                    "Rejected MMI code due to an ongoing call on another phone account."));
            return true;
        }
        return false;
    }

    private void showErrorDialogForMaxOutgoingCall(Call call) {
        call.setStartFailCause(CallFailureCause.MAX_OUTGOING_CALLS);
        int stringId = R.string.callFailed_too_many_calls;
+21 −2
Original line number Diff line number Diff line
@@ -16,21 +16,26 @@

package com.android.server.telecom.callsequencing;

import static com.android.server.telecom.CallsManager.CALL_FILTER_ALL;
import static com.android.server.telecom.CallsManager.ONGOING_CALL_STATES;

import android.content.Context;
import android.os.Bundle;
import android.os.Handler;
import android.os.OutcomeReceiver;
import android.telecom.CallAttributes;
import android.telecom.CallException;
import android.telecom.Connection;
import android.telecom.DisconnectCause;
import android.telecom.Log;

import com.android.server.telecom.Call;
import com.android.server.telecom.CallAudioManager;
import com.android.server.telecom.CallState;
import com.android.server.telecom.CallsManager;
import com.android.server.telecom.LoggedHandlerExecutor;
import com.android.server.telecom.callsequencing.voip.OutgoingCallTransaction;
import com.android.server.telecom.flags.FeatureFlags;
import com.android.server.telecom.R;

import java.util.concurrent.CompletableFuture;

@@ -41,16 +46,18 @@ import java.util.concurrent.CompletableFuture;
public class CallsManagerCallSequencingAdapter {

    private final CallsManager mCallsManager;
    private final Context mContext;
    private final CallSequencingController mSequencingController;
    private final CallAudioManager mCallAudioManager;
    private final Handler mHandler;
    private final FeatureFlags mFeatureFlags;
    private final boolean mIsCallSequencingEnabled;

    public CallsManagerCallSequencingAdapter(CallsManager callsManager,
    public CallsManagerCallSequencingAdapter(CallsManager callsManager, Context context,
            CallSequencingController sequencingController, CallAudioManager callAudioManager,
            FeatureFlags featureFlags) {
        mCallsManager = callsManager;
        mContext = context;
        mSequencingController = sequencingController;
        mCallAudioManager = callAudioManager;
        mHandler = sequencingController.getHandler();
@@ -278,6 +285,18 @@ public class CallsManagerCallSequencingAdapter {
        }
    }

    /**
     * Tries to see if there are any ongoing calls on another phone account when an MMI code is
     * detected to determine whether it should be allowed. For DSDA purposes, we will not allow any
     * MMI codes when there's a call on a different phone account.
     * @param call The call to ignore and the associated phone account to exclude when getting the
     *             total call count.
     * @return {@code true} if the MMI code should be allowed, {@code false} otherwise.
     */
    public boolean shouldAllowMmiCode(Call call) {
        return !mIsCallSequencingEnabled || !mSequencingController.hasMmiCodeRestriction(call);
    }

    public Handler getHandler() {
        return mHandler;
    }
+28 −0
Original line number Diff line number Diff line
@@ -16,6 +16,8 @@

package com.android.server.telecom.tests;

import static com.android.server.telecom.CallsManager.CALL_FILTER_ALL;
import static com.android.server.telecom.CallsManager.ONGOING_CALL_STATES;
import static com.android.server.telecom.UserUtil.showErrorDialogForRestrictedOutgoingCall;

import static junit.framework.Assert.assertNotNull;
@@ -30,6 +32,7 @@ import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.timeout;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import static org.junit.Assert.assertTrue;
@@ -46,6 +49,7 @@ import android.os.UserHandle;
import android.telecom.CallAttributes;
import android.telecom.CallException;
import android.telecom.Connection;
import android.telecom.DisconnectCause;
import android.telecom.PhoneAccount;
import android.telecom.PhoneAccountHandle;
import android.telephony.CarrierConfigManager;
@@ -574,6 +578,30 @@ public class CallSequencingTests extends TelecomTestCase {
                .processDisconnectCallAndCleanup(eq(mActiveCall), eq(previousState));
    }

    @Test
    @SmallTest
    public void testMmiCodeRestrictionReject() {
        // Verify that when calls are detected across other phone accounts,
        // that the MMI code is rejected.
        when(mNewCall.getTargetPhoneAccount()).thenReturn(mHandle1);
        when(mCallsManager.getNumCallsWithStateWithoutHandle(CALL_FILTER_ALL, mNewCall,
                mHandle1, ONGOING_CALL_STATES)).thenReturn(1);
        assertTrue(mController.hasMmiCodeRestriction(mNewCall));
        verify(mNewCall).setOverrideDisconnectCauseCode(any(DisconnectCause.class));
    }

    @Test
    @SmallTest
    public void testMmiCodeRestrictionAllow() {
        // Verify that when no calls are detected across other phone accounts,
        // that the MMI code is allowed.
        when(mNewCall.getTargetPhoneAccount()).thenReturn(mHandle1);
        when(mCallsManager.getNumCallsWithStateWithoutHandle(CALL_FILTER_ALL, mNewCall,
                mHandle1, ONGOING_CALL_STATES)).thenReturn(0);
        assertFalse(mController.hasMmiCodeRestriction(mNewCall));
        verify(mNewCall, times(0)).setOverrideDisconnectCauseCode(any(DisconnectCause.class));
    }

    /* Helpers */
    private void setPhoneAccounts(Call call1, Call call2, boolean useSamePhoneAccount) {
        when(call1.getTargetPhoneAccount()).thenReturn(mHandle1);