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

Commit 212d538a authored by Pranav Madapurmath's avatar Pranav Madapurmath
Browse files

Ensure BT ICS unbind after completing BT future

This CL ensures that once the BT disconnected tone future is completed
that we unbind from the BT ICS immediately after. There were cases where
the disconnect tone doesn't play and the only place we perform the
unbinding is when the disconnect tone finishes in
InCallController#onDisconnectedTonePlaying. We should ensure that we
always unbind the BT ICS for all cases. Once we complete the future,
we for sure know that the call state is disconnected so we can safely
unbind at that point.

This CL also makes changes to the mPendingEndCallTone set being used.
I had added logic to skip the unbinding if the set is not empty but in
cases where we don't play the disconnect tone, the associated call is
never cleaned up from the set. Looking at this closer, I also realized
that in cases where the associated user of the calls are different, the
references to the ICS connections/info would never be cleaned up
properly. We should clean up the references if there are no more calls
of the same associated user. We should also skip the unbinding in the
case that the user used to bind to the BT ICS is the same even when the
associated users of any two calls are differnet. From my understanding,
we always bind to BT ICS as User 0 but it's better not to hardcode that
assumption into the implementation details.

Bug: 374933312
Test: Manual to verify that unbinding takes place in cases where we
don't play the disconnect tone.
Flag: EXEMPT bugfix

Change-Id: I49481a3dcd3bc0aa92f1d86ffc1de7a80a9e89c4
parent 6b2d00fc
Loading
Loading
Loading
Loading
+3 −0
Original line number Diff line number Diff line
@@ -1101,6 +1101,9 @@ public class CallAudioManager extends CallsManagerListenerBase {
                    call.getId());
            disconnectedToneFuture.complete(null);
        }
        // Make sure we schedule the unbinding of the BT ICS once the disconnected tone future has
        // been completed.
        mCallsManager.getInCallController().maybeScheduleBtUnbind(call);
    }

    @VisibleForTesting
+80 −39
Original line number Diff line number Diff line
@@ -305,7 +305,7 @@ public class InCallController extends CallsManagerListenerBase implements

        //this is really used for cases where the userhandle for a call
        //does not match what we want to use for bindAsUser
        private final UserHandle mUserHandleToUseForBinding;
        private UserHandle mUserHandleToUseForBinding;

        public InCallServiceBindingConnection(InCallServiceInfo info) {
            mInCallServiceInfo = info;
@@ -388,6 +388,8 @@ public class InCallController extends CallsManagerListenerBase implements
                                    + "INTERACT_ACROSS_USERS permission");
                }
            }
            // Used for referencing what user we used to bind to the given ICS.
            mUserHandleToUseForBinding = userToBind;
            Log.i(this, "using user id: %s for binding. User from Call is: %s", userToBind,
                    userFromCall);
            if (!mContext.bindServiceAsUser(intent, mServiceConnection,
@@ -1230,7 +1232,7 @@ public class InCallController extends CallsManagerListenerBase implements
            mCombinedInCallServiceMap = new ArrayMap<>();

    private final CallIdMapper mCallIdMapper = new CallIdMapper(Call::getId);
    private final Collection<Call> mPendingEndToneCall = new ArraySet<>();
    private final Collection<Call> mBtIcsCallTracker = new ArraySet<>();

    private final Context mContext;
    private final AppOpsManager mAppOpsManager;
@@ -1246,7 +1248,7 @@ public class InCallController extends CallsManagerListenerBase implements
            mInCallServiceConnections = new ArrayMap<>();
    private final Map<UserHandle, NonUIInCallServiceConnectionCollection>
            mNonUIInCallServiceConnections = new ArrayMap<>();
    private final Map<UserHandle, InCallServiceConnection> mBTInCallServiceConnections =
    private final Map<UserHandle, InCallServiceBindingConnection> mBTInCallServiceConnections =
            new ArrayMap<>();
    private final ClockProxy mClockProxy;
    private final IBinder mToken = new Binder();
@@ -1421,6 +1423,7 @@ public class InCallController extends CallsManagerListenerBase implements
                bindingToBtRequired = true;
                bindToBTService(call, null);
            }

            if (!isBoundAndConnectedToServices(userFromCall)) {
                Log.i(this, "onCallAdded: %s; not bound or connected to other ICS.", call);
                // We are not bound, or we're not connected.
@@ -1565,20 +1568,61 @@ public class InCallController extends CallsManagerListenerBase implements
                                + "disconnected tone future");
                        mDisconnectedToneBtFutures.get(call.getId()).complete(null);
                    }
                    mPendingEndToneCall.remove(call);
                    if (!mPendingEndToneCall.isEmpty()) {
                        return;
                    // Schedule unbinding of BT ICS.
                    maybeScheduleBtUnbind(call);
                }
            }
        }
    }

    public void maybeScheduleBtUnbind(Call call) {
        mBtIcsCallTracker.remove(call);
        // Track the current calls that are being tracked by the BT ICS and determine the
        // associated users of those calls as well as the users which have been used to bind to the
        // ICS.
        Set<UserHandle> usersFromOngoingCalls = new ArraySet<>();
        Set<UserHandle> usersCurrentlyBound = new ArraySet<>();
        for (Call pendingCall : mBtIcsCallTracker) {
            UserHandle userFromPendingCall = getUserFromCall(pendingCall);
            final InCallServiceBindingConnection pendingCallConnection =
                    mBTInCallServiceConnections.get(userFromPendingCall);
            usersFromOngoingCalls.add(userFromPendingCall);
            if (pendingCallConnection != null) {
                usersCurrentlyBound.add(pendingCallConnection.mUserHandleToUseForBinding);
            }
        }

        UserHandle userHandle = getUserFromCall(call);
        // Refrain from unbinding ICS and clearing the ICS mapping if there's an ongoing call under
        // the same associated user. Make sure we keep the internal mappings so that they aren't
        // cleared until that call is disconnected. Note here that if the associated users are the
        // same, the user used for the binding will also be the same.
        if (usersFromOngoingCalls.contains(userHandle)) {
            Log.i(this, "scheduleBtUnbind: Refraining from unbinding BT service due to an ongoing "
                    + "call detected under the same user (%s).", userHandle);
            return;
        }

        if (mBTInCallServiceConnections.containsKey(userHandle)) {
                        Log.i(this, "onDisconnectedTonePlaying: Schedule unbind BT service");
                        final InCallServiceConnection connection =
            Log.i(this, "scheduleBtUnbind: Schedule unbind BT service");
            final InCallServiceBindingConnection connection =
                    mBTInCallServiceConnections.get(userHandle);

            // The user that was used for binding may be different than the user from call
            // (associated user), which is what we use to reference the BT ICS bindings. For
            // example, consider the work profile scenario where the BT ICS is only available under
            // User 0: in this case, the user to bind to will be User 0 whereas we store the
            // references to this connection and BT ICS under the work user. This logic ensures
            // that we prevent unbinding the BT ICS if there is a personal (associatedUser: 0) call
            // + work call (associatedUser: 10) and one of them gets disconnected.
            if (usersCurrentlyBound.contains(connection.mUserHandleToUseForBinding)) {
                Log.i(this, "scheduleBtUnbind: Refraining from unbinding BT service to an "
                        + "ongoing call detected which is bound to the same user (%s).",
                        connection.mUserHandleToUseForBinding);
            } else {
                // Similar to in onCallRemoved when we unbind from the other ICS, we need to
                // delay unbinding from the BT ICS because we need to give the ICS a
                // moment to finish the onCallRemoved signal it got just prior.
                        mHandler.postDelayed(new Runnable("ICC.oDCTP", mLock) {
                mHandler.postDelayed(new Runnable("ICC.sBU", mLock) {
                    @Override
                    public void loggedRun() {
                        Log.i(this, "onDisconnectedTonePlaying: unbinding from BT ICS.");
@@ -1594,7 +1638,7 @@ public class InCallController extends CallsManagerListenerBase implements
                    }
                }.prepare(), mTimeoutsAdapter.getCallRemoveUnbindInCallServicesDelay(
                        mContext.getContentResolver()));

            }
            mBTInCallServiceConnections.remove(userHandle);
        }
        // Ensure that BT ICS instance is cleaned up
@@ -1602,9 +1646,6 @@ public class InCallController extends CallsManagerListenerBase implements
            updateCombinedInCallServiceMap(userHandle);
        }
    }
            }
        }
    }

    @Override
    public void onExternalCallChanged(Call call, boolean isExternalCall) {
@@ -2841,7 +2882,7 @@ public class InCallController extends CallsManagerListenerBase implements
            mCallIdMapper.addCall(call);
            call.addListener(mCallListener);
            if (mFeatureFlags.separatelyBindToBtIncallService()) {
                mPendingEndToneCall.add(call);
                mBtIcsCallTracker.add(call);
            }
        }