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

Commit 29b87774 authored by Pranav Madapurmath's avatar Pranav Madapurmath
Browse files

Enforce consistent user retrieval for ICS updates.

In InCallController, getUserFromCall is being leveraged in various areas
to get the corresponding user which is used to store references to the
ongoing connections. Typically, this is extracted from the UserHandle
stored in the target phone account but this may not be set if the user
has not selected a default sim and there are multiple accounts which can
be used to place the call. As fallback in the situations, we used the
current user so the connection would be referencable using that user
only. Once the target account is set (and if that user is different from
the current user), we would end up trying to retrieve the ICS for that
user which would result in a bunch of no-ops in the call flow.

As a solution, we can ensure that the UserHandle retrieved for any given
call by getUserFromCall will always be consistent for the entirety of
the call. For MT calls, the target phone account is always set so we can
use that. For MO calls, since there's a possibility that the target
phone account isn't set, we can use the initiating user instead. Note
that for any call, the phone account used would either be associated
with the user placing the call or not. In the latter case, we should
still use the initiating user so that we can report that as such in
dialer.

This points out a deeper problem in Telecom where we are interchangeably
using Call#getInitiatingUser and
Call#getUserHandleFromTargetPhoneAccount, without enforcing the
possibility that the target phone account is never set if a default sim
isn't selected. In order to consolidate the logic to determine the user
association with the call, I have replaced mInitiatingUser with
mAssociatedUser, which essentially tracks the associated user for any
given call (i.e. initiating user for MO, target phone account user for
MT). Also note that for conference calls and existing connections, we
will continue to base the user association with the target phone account
user.

Fixes: 284403805
Test: Created a failing test which tests that the connection is not
      removed from the mapping when the call is removed before the
      updates.
Test: Unit test to ensure that the user retrieval in getUserFromCall is
      consistent when the target phone account is not initially set.
Test: Modified existing unit tests, atest TelecomUnitTests
Test: Manual testing on secondary user with no default sim to verify
      in-call UI is visible and accessible.
Change-Id: I262344ae555c790eae6e6e37b664694a9ce859e3
parent 6ade6d1d
Loading
Loading
Loading
Loading
+23 −18
Original line number Diff line number Diff line
@@ -362,7 +362,7 @@ public class Call implements CreateConnectionResponse, EventManager.Loggable,

    private PhoneAccountHandle mRemotePhoneAccountHandle;

    private UserHandle mInitiatingUser;
    private UserHandle mAssociatedUser;

    private final Handler mHandler = new Handler(Looper.getMainLooper());

@@ -830,8 +830,8 @@ public class Call implements CreateConnectionResponse, EventManager.Loggable,
                ? PhoneNumberUtils.extractPostDialPortion(handle.getSchemeSpecificPart()) : "";
        mGatewayInfo = gatewayInfo;
        setConnectionManagerPhoneAccount(connectionManagerPhoneAccountHandle);
        setTargetPhoneAccount(targetPhoneAccountHandle);
        mCallDirection = callDirection;
        setTargetPhoneAccount(targetPhoneAccountHandle);
        mIsConference = isConference;
        mShouldAttachToExistingConnection = shouldAttachToExistingConnection
                || callDirection == CALL_DIRECTION_INCOMING;
@@ -1005,7 +1005,7 @@ public class Call implements CreateConnectionResponse, EventManager.Loggable,
        s.append("]");
        s.append(isIncoming() ? "(MT - incoming)" : "(MO - outgoing)");
        s.append("(User=");
        s.append(getInitiatingUser());
        s.append(getAssociatedUser());
        s.append(")");
        s.append("\n\t");

@@ -1732,13 +1732,11 @@ public class Call implements CreateConnectionResponse, EventManager.Loggable,
            mCallStateChangedAtomWriter.setUid(
                    accountHandle.getComponentName().getPackageName(),
                    mContext.getPackageManager());
            // Set the associated user for the call for MT calls based on the target phone account.
            if (isIncoming() && !accountHandle.getUserHandle().equals(mAssociatedUser)) {
                setAssociatedUser(accountHandle.getUserHandle());
            }
        }

    public UserHandle getUserHandleFromTargetPhoneAccount() {
        return mTargetPhoneAccountHandle == null
                ? mCallsManager.getCurrentUserHandle() :
                mTargetPhoneAccountHandle.getUserHandle();
    }

    public PhoneAccount getPhoneAccountFromHandle() {
@@ -1985,7 +1983,7 @@ public class Call implements CreateConnectionResponse, EventManager.Loggable,
        if (phoneAccount != null) {
            final UserHandle userHandle;
            if (phoneAccount.hasCapabilities(PhoneAccount.CAPABILITY_MULTI_USER)) {
                userHandle = mInitiatingUser;
                userHandle = mAssociatedUser;
            } else {
                userHandle = mTargetPhoneAccountHandle.getUserHandle();
            }
@@ -4017,19 +4015,26 @@ public class Call implements CreateConnectionResponse, EventManager.Loggable,
    }

    /**
     * @return user handle of user initiating the outgoing call.
     * It's possible that the target phone account isn't set when a user hasn't selected a
     * default sim to place a call. Instead of using the user from the target phone account to
     * associate the user with a call, we'll use mAssociatedUser instead. For MT calls, we will
     * continue to use the target phone account user (as it's always set) and for MO calls, we will
     * use the initiating user instead.
     *
     * @return user handle of user associated with the call.
     */
    public UserHandle getInitiatingUser() {
        return mInitiatingUser;
    public UserHandle getAssociatedUser() {
        return mAssociatedUser;
    }

    /**
     * Set the user handle of user initiating the outgoing call.
     * @param initiatingUser
     * Set the user handle of user associated with the call.
     * @param associatedUser
     */
    public void setInitiatingUser(UserHandle initiatingUser) {
        Preconditions.checkNotNull(initiatingUser);
        mInitiatingUser = initiatingUser;
    public void setAssociatedUser(UserHandle associatedUser) {
        Log.i(this, "Setting associated user for call");
        Preconditions.checkNotNull(associatedUser);
        mAssociatedUser = associatedUser;
    }

    static int getStateFromConnectionState(int state) {
+1 −1
Original line number Diff line number Diff line
@@ -497,7 +497,7 @@ public class CallAudioManager extends CallsManagerListenerBase {
        boolean allCallSilenced = true;
        synchronized (mCallsManager.getLock()) {
            for (Call call : mRingingCalls) {
                UserHandle userFromCall = call.getUserHandleFromTargetPhoneAccount();
                UserHandle userFromCall = call.getAssociatedUser();
                // Do not try to silence calls when calling user is different from the phone account
                // user, the account does not have CAPABILITY_MULTI_USER enabled, or if the user
                // does not have the INTERACT_ACROSS_USERS permission enabled.
+1 −1
Original line number Diff line number Diff line
@@ -324,7 +324,7 @@ public final class CallLogManager extends CallsManagerListenerBase {
        }

        PhoneAccount phoneAccount = mPhoneAccountRegistrar.getPhoneAccountUnchecked(accountHandle);
        UserHandle initiatingUser = call.getInitiatingUser();
        UserHandle initiatingUser = call.getAssociatedUser();
        if (phoneAccount != null &&
                phoneAccount.hasCapabilities(PhoneAccount.CAPABILITY_MULTI_USER)) {
            if (initiatingUser != null &&
+1 −1
Original line number Diff line number Diff line
@@ -182,7 +182,7 @@ public class CallStreamingController extends CallsManagerListenerBase {
            super(mTelecomLock);
            mWrapper = wrapper;
            mCall = call;
            mUserHandle = mCall.getInitiatingUser();
            mUserHandle = mCall.getAssociatedUser();
            mContext = context;
        }

+26 −14
Original line number Diff line number Diff line
@@ -736,7 +736,7 @@ public class CallsManager extends Call.ListenerBase
    public void onSuccessfulOutgoingCall(Call call, int callState) {
        Log.v(this, "onSuccessfulOutgoingCall, %s", call);
        call.setPostCallPackageName(getRoleManagerAdapter().getDefaultCallScreeningApp(
                call.getUserHandleFromTargetPhoneAccount()));
                call.getAssociatedUser()));

        setCallState(call, callState, "successful outgoing call");
        if (!mCalls.contains(call)) {
@@ -800,7 +800,7 @@ public class CallsManager extends Call.ListenerBase
    private IncomingCallFilterGraph setUpCallFilterGraph(Call incomingCall) {
        incomingCall.setIsUsingCallFiltering(true);
        String carrierPackageName = getCarrierPackageName();
        UserHandle userHandle = incomingCall.getUserHandleFromTargetPhoneAccount();
        UserHandle userHandle = incomingCall.getAssociatedUser();
        String defaultDialerPackageName = TelecomManager.from(mContext).
                getDefaultDialerPackage(userHandle);
        String userChosenPackageName = getRoleManagerAdapter().
@@ -922,7 +922,7 @@ public class CallsManager extends Call.ListenerBase
        if (result.shouldAllowCall) {
            incomingCall.setPostCallPackageName(
                    getRoleManagerAdapter().getDefaultCallScreeningApp(
                            incomingCall.getUserHandleFromTargetPhoneAccount()
                            incomingCall.getAssociatedUser()
                    ));

            Log.i(this, "onCallFilteringComplete: allow call.");
@@ -1431,7 +1431,7 @@ public class CallsManager extends Call.ListenerBase
                }
            }
            // Incoming address was set via EXTRA_INCOMING_CALL_ADDRESS above.
            call.setInitiatingUser(phoneAccountHandle.getUserHandle());
            call.setAssociatedUser(phoneAccountHandle.getUserHandle());
        }

        // Ensure new calls related to self-managed calls/connections are set as such. This will
@@ -1558,7 +1558,7 @@ public class CallsManager extends Call.ListenerBase
        // Check if the target phone account is possibly in ECBM.
        call.setIsInECBM(getEmergencyCallHelper()
                .isLastOutgoingEmergencyCallPAH(call.getTargetPhoneAccount()));
        if (mUserManager.isQuietModeEnabled(call.getUserHandleFromTargetPhoneAccount())
        if (mUserManager.isQuietModeEnabled(call.getAssociatedUser())
                && !call.isEmergencyCall() && !call.isInECBM()) {
            Log.d(TAG, "Rejecting non-emergency call because the owner %s is not running.",
                    phoneAccountHandle.getUserHandle());
@@ -1635,6 +1635,8 @@ public class CallsManager extends Call.ListenerBase
                mToastFactory);
        call.initAnalytics();

        // For unknown calls, base the associated user off of the target phone account handle.
        call.setAssociatedUser(phoneAccountHandle.getUserHandle());
        setIntentExtrasAndStartTime(call, extras);
        call.addListener(this);
        notifyStartCreateConnection(call);
@@ -1798,7 +1800,7 @@ public class CallsManager extends Call.ListenerBase
                        || phoneAccountExtra.getBoolean(
                                PhoneAccount.EXTRA_ADD_SELF_MANAGED_CALLS_TO_INCALLSERVICE, true));
            }
            call.setInitiatingUser(initiatingUser);
            call.setAssociatedUser(initiatingUser);
            isReusedCall = false;
        } else {
            isReusedCall = true;
@@ -2074,7 +2076,7 @@ public class CallsManager extends Call.ListenerBase
                    (callPhoneAccountHandlePair, uriCallerInfoPair) -> {
                        Call theCall = callPhoneAccountHandlePair.first;
                        UserHandle userHandleForCallScreening = theCall.
                                getUserHandleFromTargetPhoneAccount();
                                getAssociatedUser();
                        boolean isInContacts = uriCallerInfoPair.second != null
                                && uriCallerInfoPair.second.contactExists;
                        Log.d(CallsManager.this, "outgoingCallIdStage: isInContacts=%s",
@@ -2309,7 +2311,7 @@ public class CallsManager extends Call.ListenerBase
        // Find the user chosen call screening app.
        String callScreeningApp =
                mRoleManagerAdapter.getDefaultCallScreeningApp(
                        theCall.getUserHandleFromTargetPhoneAccount());
                        theCall.getAssociatedUser());

        CompletableFuture future =
                new CallScreeningServiceHelper(mContext,
@@ -2473,7 +2475,7 @@ public class CallsManager extends Call.ListenerBase
                && !phoneAccount.hasCapabilities(PhoneAccount.CAPABILITY_MULTI_USER)) {
            // Note that mCurrentUserHandle may not actually be the current user, i.e.
            // in the case of work profiles
            UserHandle currentUserHandle = call.getUserHandleFromTargetPhoneAccount();
            UserHandle currentUserHandle = call.getAssociatedUser();
            // Check if the phoneAccountHandle belongs to the current user
            if (phoneAccountHandle != null &&
                    !phoneAccountHandle.getUserHandle().equals(currentUserHandle)) {
@@ -2756,7 +2758,7 @@ public class CallsManager extends Call.ListenerBase
        // Auto-enable speakerphone if the originating intent specified to do so, if the call
        // is a video call, of if using speaker when docked
        PhoneAccount account = mPhoneAccountRegistrar.getPhoneAccount(
                call.getTargetPhoneAccount(), call.getInitiatingUser());
                call.getTargetPhoneAccount(), call.getAssociatedUser());
        boolean allowVideo = false;
        if (account != null) {
            allowVideo = account.hasCapabilities(PhoneAccount.CAPABILITY_VIDEO_CALLING);
@@ -2818,7 +2820,7 @@ public class CallsManager extends Call.ListenerBase
            }
        } else if (mPhoneAccountRegistrar.getCallCapablePhoneAccounts(
                requireCallCapableAccountByHandle ? callHandleScheme : null, false,
                call.getInitiatingUser(), false).isEmpty()) {
                call.getAssociatedUser(), false).isEmpty()) {
            // If there are no call capable accounts, disconnect the call.
            markCallAsDisconnected(call, new DisconnectCause(DisconnectCause.CANCELED,
                    "No registered PhoneAccounts"));
@@ -3439,7 +3441,7 @@ public class CallsManager extends Call.ListenerBase
        } else {
            if (setDefault) {
                mPhoneAccountRegistrar
                        .setUserSelectedOutgoingPhoneAccount(account, call.getInitiatingUser());
                        .setUserSelectedOutgoingPhoneAccount(account, call.getAssociatedUser());
            }

            if (mPendingAccountSelection != null) {
@@ -4145,6 +4147,8 @@ public class CallsManager extends Call.ListenerBase
        call.setVideoProvider(parcelableConference.getVideoProvider());
        call.setStatusHints(parcelableConference.getStatusHints());
        call.putConnectionServiceExtras(parcelableConference.getExtras());
        // For conference calls, set the associated user from the target phone account user handle.
        call.setAssociatedUser(phoneAccount.getUserHandle());
        // In case this Conference was added via a ConnectionManager, keep track of the original
        // Connection ID as created by the originating ConnectionService.
        Bundle extras = parcelableConference.getExtras();
@@ -5182,6 +5186,9 @@ public class CallsManager extends Call.ListenerBase
        call.setHandle(connection.getHandle(), connection.getHandlePresentation());
        call.setCallerDisplayName(connection.getCallerDisplayName(),
                connection.getCallerDisplayNamePresentation());
        // For existing connections, use the phone account user handle to determine the user
        // association with the call.
        call.setAssociatedUser(connection.getPhoneAccount().getUserHandle());
        call.addListener(this);
        call.putConnectionServiceExtras(connection.getExtras());

@@ -5831,7 +5838,9 @@ public class CallsManager extends Call.ListenerBase
        if (isSelfManaged) {
            call.setIsVoipAudioMode(true);
        }
        call.setInitiatingUser(getCurrentUserHandle());
        // Set associated user based on the existing call as it doesn't make sense to handover calls
        // across user profiles.
        call.setAssociatedUser(handoverFromCall.getAssociatedUser());

        // Ensure we don't try to place an outgoing call with video if video is not
        // supported.
@@ -6065,6 +6074,9 @@ public class CallsManager extends Call.ListenerBase
        fromCall.setHandoverDestinationCall(call);
        call.setHandoverSourceCall(fromCall);
        call.setHandoverState(HandoverState.HANDOVER_TO_STARTED);
        // Set associated user based on the existing call as it doesn't make sense to handover calls
        // across user profiles.
        call.setAssociatedUser(fromCall.getAssociatedUser());
        fromCall.setHandoverState(HandoverState.HANDOVER_FROM_STARTED);

        if (isSpeakerEnabledForVideoCalls() && VideoProfile.isVideo(videoState)) {
@@ -6351,7 +6363,7 @@ public class CallsManager extends Call.ListenerBase
     * @return {@code true} if call is visible to the calling user
     */
    boolean isCallVisibleForUser(Call call, UserHandle userHandle) {
        return call.getUserHandleFromTargetPhoneAccount().equals(userHandle)
        return call.getAssociatedUser().equals(userHandle)
                || call.getPhoneAccountFromHandle()
                .hasCapabilities(PhoneAccount.CAPABILITY_MULTI_USER);
    }
Loading