diff options
Diffstat (limited to 'src')
10 files changed, 216 insertions, 65 deletions
diff --git a/src/com/android/server/telecom/Call.java b/src/com/android/server/telecom/Call.java index 6e4dc3ce5..7ef2a12a4 100644 --- a/src/com/android/server/telecom/Call.java +++ b/src/com/android/server/telecom/Call.java @@ -23,6 +23,7 @@ import android.annotation.NonNull; import android.annotation.Nullable; import android.content.Context; import android.content.Intent; +import android.content.pm.PackageManager; import android.graphics.Bitmap; import android.graphics.drawable.Drawable; import android.net.Uri; @@ -72,6 +73,7 @@ import android.widget.Toast; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.telecom.IVideoProvider; import com.android.internal.util.Preconditions; +import com.android.server.telecom.flags.FeatureFlags; import com.android.server.telecom.stats.CallFailureCause; import com.android.server.telecom.stats.CallStateChangedAtomWriter; import com.android.server.telecom.ui.ToastFactory; @@ -324,6 +326,7 @@ public class Call implements CreateConnectionResponse, EventManager.Loggable, } }; + private final boolean mIsModifyStatePermissionGranted; /** * One of CALL_DIRECTION_INCOMING, CALL_DIRECTION_OUTGOING, or CALL_DIRECTION_UNKNOWN */ @@ -786,6 +789,8 @@ public class Call implements CreateConnectionResponse, EventManager.Loggable, */ private CompletableFuture<Boolean> mDisconnectFuture; + private FeatureFlags mFlags; + /** * Persists the specified parameters and initializes the new instance. * @param context The context. @@ -817,11 +822,12 @@ public class Call implements CreateConnectionResponse, EventManager.Loggable, boolean shouldAttachToExistingConnection, boolean isConference, ClockProxy clockProxy, - ToastFactory toastFactory) { + ToastFactory toastFactory, + FeatureFlags featureFlags) { this(callId, context, callsManager, lock, repository, phoneNumberUtilsAdapter, handle, null, gatewayInfo, connectionManagerPhoneAccountHandle, targetPhoneAccountHandle, callDirection, shouldAttachToExistingConnection, - isConference, clockProxy, toastFactory); + isConference, clockProxy, toastFactory, featureFlags); } @@ -841,8 +847,10 @@ public class Call implements CreateConnectionResponse, EventManager.Loggable, boolean shouldAttachToExistingConnection, boolean isConference, ClockProxy clockProxy, - ToastFactory toastFactory) { + ToastFactory toastFactory, + FeatureFlags featureFlags) { + mFlags = featureFlags; mId = callId; mConnectionId = callId; mState = (isConference && callDirection != CALL_DIRECTION_INCOMING && @@ -873,6 +881,8 @@ public class Call implements CreateConnectionResponse, EventManager.Loggable, mStartRingTime = 0; mCallStateChangedAtomWriter.setExistingCallCount(callsManager.getCalls().size()); + mIsModifyStatePermissionGranted = + isModifyPhoneStatePermissionGranted(getDelegatePhoneAccountHandle()); } /** @@ -892,6 +902,7 @@ public class Call implements CreateConnectionResponse, EventManager.Loggable, * connection, regardless of whether it's incoming or outgoing. * @param connectTimeMillis The connection time of the call. * @param clockProxy + * @param featureFlags The telecom feature flags. */ Call( String callId, @@ -910,11 +921,13 @@ public class Call implements CreateConnectionResponse, EventManager.Loggable, long connectTimeMillis, long connectElapsedTimeMillis, ClockProxy clockProxy, - ToastFactory toastFactory) { + ToastFactory toastFactory, + FeatureFlags featureFlags) { this(callId, context, callsManager, lock, repository, phoneNumberUtilsAdapter, handle, gatewayInfo, connectionManagerPhoneAccountHandle, targetPhoneAccountHandle, callDirection, - shouldAttachToExistingConnection, isConference, clockProxy, toastFactory); + shouldAttachToExistingConnection, isConference, clockProxy, toastFactory, + featureFlags); mConnectTimeMillis = connectTimeMillis; mConnectElapsedTimeMillis = connectElapsedTimeMillis; @@ -1766,8 +1779,12 @@ public class Call implements CreateConnectionResponse, EventManager.Loggable, 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()); + UserHandle associatedUser = UserUtil.getAssociatedUserForCall( + mFlags.workProfileAssociatedUser(), + mCallsManager.getPhoneAccountRegistrar(), mCallsManager.getCurrentUserHandle(), + accountHandle); + if (isIncoming() && !associatedUser.equals(mAssociatedUser)) { + setAssociatedUser(associatedUser); } } } @@ -3098,6 +3115,12 @@ public class Call implements CreateConnectionResponse, EventManager.Loggable, Connection.EXTRA_REMOTE_PHONE_ACCOUNT_HANDLE)); } + if (mExtras.containsKey(TelecomManager.EXTRA_DO_NOT_LOG_CALL)) { + if (source != SOURCE_CONNECTION_SERVICE || !mIsModifyStatePermissionGranted) { + mExtras.remove(TelecomManager.EXTRA_DO_NOT_LOG_CALL); + } + } + // If the change originated from an InCallService, notify the connection service. if (source == SOURCE_INCALL_SERVICE) { Log.addEvent(this, LogUtils.Events.ICS_EXTRAS_CHANGED); @@ -3112,6 +3135,15 @@ public class Call implements CreateConnectionResponse, EventManager.Loggable, } } + private boolean isModifyPhoneStatePermissionGranted(PhoneAccountHandle phoneAccountHandle) { + if (phoneAccountHandle == null) { + return false; + } + String packageName = phoneAccountHandle.getComponentName().getPackageName(); + return PackageManager.PERMISSION_GRANTED == mContext.getPackageManager().checkPermission( + android.Manifest.permission.MODIFY_PHONE_STATE, packageName); + } + /** * Removes extras from the extras bundle associated with this {@link Call}. * @@ -4092,7 +4124,7 @@ public class Call implements CreateConnectionResponse, EventManager.Loggable, * @param associatedUser */ public void setAssociatedUser(UserHandle associatedUser) { - Log.i(this, "Setting associated user for call"); + Log.i(this, "Setting associated user for call: %s", associatedUser); Preconditions.checkNotNull(associatedUser); mAssociatedUser = associatedUser; } diff --git a/src/com/android/server/telecom/CallAudioCommunicationDeviceTracker.java b/src/com/android/server/telecom/CallAudioCommunicationDeviceTracker.java index 38a96eb3e..5fc241446 100644 --- a/src/com/android/server/telecom/CallAudioCommunicationDeviceTracker.java +++ b/src/com/android/server/telecom/CallAudioCommunicationDeviceTracker.java @@ -24,10 +24,12 @@ import android.telecom.Log; import com.android.internal.annotations.VisibleForTesting; import com.android.server.telecom.bluetooth.BluetoothRouteManager; +import com.android.server.telecom.flags.Flags; import java.util.Arrays; import java.util.List; import java.util.Set; +import java.util.concurrent.Semaphore; /** * Helper class used to keep track of the requested communication device within Telecom for audio @@ -50,6 +52,7 @@ public class CallAudioCommunicationDeviceTracker { private int mAudioDeviceType = sAUDIO_DEVICE_TYPE_INVALID; // Keep track of the locally requested BT audio device if set private String mBtAudioDevice = null; + private final Semaphore mLock = new Semaphore(1); public CallAudioCommunicationDeviceTracker(Context context) { mAudioManager = context.getSystemService(AudioManager.class); @@ -94,6 +97,9 @@ public class CallAudioCommunicationDeviceTracker { */ public boolean setCommunicationDevice(int audioDeviceType, BluetoothDevice btDevice) { + if (Flags.communicationDeviceProtectedByLock()) { + mLock.tryAcquire(); + } // There is only one audio device type associated with each type of BT device. boolean isBtDevice = sBT_AUDIO_DEVICE_TYPES.contains(audioDeviceType); Log.i(this, "setCommunicationDevice: type = %s, isBtDevice = %s, btDevice = %s", @@ -153,8 +159,16 @@ public class CallAudioCommunicationDeviceTracker { if (audioDeviceType == AudioDeviceInfo.TYPE_BLE_HEADSET) { mBluetoothRouteManager.onAudioOn(mBtAudioDevice); } + } else if (Flags.communicationDeviceProtectedByLock()) { + // Clear BT device if it's still stored. Handles race condition for when a non-BT + // device is set for communication shortly after a BT (LE) device is set for + // communication but the selection hasn't been cleared yet. + mBtAudioDevice = null; } } + if (Flags.communicationDeviceProtectedByLock()) { + mLock.release(); + } return result; } @@ -164,6 +178,9 @@ public class CallAudioCommunicationDeviceTracker { * @param audioDeviceTypes The supported audio device types for the device. */ public void clearCommunicationDevice(int audioDeviceType) { + if (Flags.communicationDeviceProtectedByLock()) { + mLock.tryAcquire(); + } // There is only one audio device type associated with each type of BT device. boolean isBtDevice = sBT_AUDIO_DEVICE_TYPES.contains(audioDeviceType); Log.i(this, "clearCommunicationDevice: type = %s, isBtDevice = %s", @@ -195,6 +212,9 @@ public class CallAudioCommunicationDeviceTracker { mBluetoothRouteManager.onAudioLost(mBtAudioDevice); mBtAudioDevice = null; } + if (Flags.communicationDeviceProtectedByLock()) { + mLock.release(); + } } private boolean isUsbHeadsetType(int audioDeviceType, int sourceType) { diff --git a/src/com/android/server/telecom/CallAudioRouteStateMachine.java b/src/com/android/server/telecom/CallAudioRouteStateMachine.java index cc5ee05f3..c0bb50e2f 100644 --- a/src/com/android/server/telecom/CallAudioRouteStateMachine.java +++ b/src/com/android/server/telecom/CallAudioRouteStateMachine.java @@ -17,7 +17,6 @@ package com.android.server.telecom; -import android.annotation.FlaggedApi; import android.app.ActivityManager; import android.bluetooth.BluetoothDevice; import android.content.BroadcastReceiver; @@ -840,6 +839,9 @@ public class CallAudioRouteStateMachine extends StateMachine implements CallAudi if (mFeatureFlags.callAudioCommunicationDeviceRefactor()) { setBluetoothOn(null); } + if (mFeatureFlags.updateRouteMaskWhenBtConnected()) { + mAvailableRoutes |= ROUTE_BLUETOOTH; + } CallAudioState newState = new CallAudioState(mIsMuted, ROUTE_BLUETOOTH, mAvailableRoutes, mBluetoothRouteManager.getBluetoothAudioConnectedDevice(), mBluetoothRouteManager.getConnectedDevices()); @@ -945,7 +947,7 @@ public class CallAudioRouteStateMachine extends StateMachine implements CallAudi mBluetoothRouteManager.disconnectAudio(); } else { mBluetoothRouteManager.disconnectAudio(); - transitionTo(mQuiescentBluetoothRoute); + reinitialize(); } mCallAudioManager.notifyAudioOperationsComplete(); } else if (msg.arg1 == RINGING_FOCUS @@ -1071,6 +1073,9 @@ public class CallAudioRouteStateMachine extends StateMachine implements CallAudi public void enter() { super.enter(); mHasUserExplicitlyLeftBluetooth = false; + if (mFeatureFlags.resetMuteWhenEnteringQuiescentBtRoute()) { + setMuteOn(false); + } updateInternalCallAudioState(); } @@ -1839,7 +1844,7 @@ public class CallAudioRouteStateMachine extends StateMachine implements CallAudi AudioDeviceInfo.TYPE_BUILTIN_SPEAKER); } } else { - processLegacySpeakerCommunicationDevice(on); + speakerOn = processLegacySpeakerCommunicationDevice(on); } mStatusBarNotifier.notifySpeakerphone(hasAnyCalls && speakerOn); } diff --git a/src/com/android/server/telecom/CallLogManager.java b/src/com/android/server/telecom/CallLogManager.java index cfa2eb40a..fc4e05d69 100644 --- a/src/com/android/server/telecom/CallLogManager.java +++ b/src/com/android/server/telecom/CallLogManager.java @@ -170,6 +170,7 @@ public final class CallLogManager extends CallsManagerListenerBase { * Call was NOT in the "choose account" phase when disconnected * Call is NOT a conference call which had children (unless it was remotely hosted). * Call is NOT a child call from a conference which was remotely hosted. + * Call has NOT indicated it should be skipped for logging in its extras * Call is NOT simulating a single party conference. * Call was NOT explicitly canceled, except for disconnecting from a conference. * Call is NOT an external call or an external call on watch. @@ -201,6 +202,11 @@ public final class CallLogManager extends CallsManagerListenerBase { return false; } + if (mFeatureFlags.telecomSkipLogBasedOnExtra() && call.getExtras() != null + && call.getExtras().containsKey(TelecomManager.EXTRA_DO_NOT_LOG_CALL)) { + return false; + } + // A child call of a conference which was remotely hosted; these didn't originate on this // device and should not be logged. if (call.getParentCall() != null && call.hasProperty(Connection.PROPERTY_REMOTELY_HOSTED)) { diff --git a/src/com/android/server/telecom/CallsManager.java b/src/com/android/server/telecom/CallsManager.java index 7fea8e04f..5db59c4af 100755 --- a/src/com/android/server/telecom/CallsManager.java +++ b/src/com/android/server/telecom/CallsManager.java @@ -685,10 +685,15 @@ public class CallsManager extends Call.ListenerBase mCallStreamingNotification = callStreamingNotification; mFeatureFlags = featureFlags; - mListeners.add(mInCallController); + if (mFeatureFlags.useImprovedListenerOrder()) { + mListeners.add(mInCallController); + } mListeners.add(mInCallWakeLockController); mListeners.add(statusBarNotifier); mListeners.add(mCallLogManager); + if (!mFeatureFlags.useImprovedListenerOrder()) { + mListeners.add(mInCallController); + } mListeners.add(mCallEndpointController); mListeners.add(mCallDiagnosticServiceController); mListeners.add(mCallAudioManager); @@ -767,6 +772,10 @@ public class CallsManager extends Call.ListenerBase call.setPostCallPackageName(getRoleManagerAdapter().getDefaultCallScreeningApp( call.getAssociatedUser())); + if (!mFeatureFlags.fixAudioFlickerForOutgoingCalls()) { + setCallState(call, callState, "successful outgoing call"); + } + if (!mCalls.contains(call)) { // Call was not added previously in startOutgoingCall due to it being a potential MMI // code, so add it now. @@ -778,11 +787,16 @@ public class CallsManager extends Call.ListenerBase listener.onConnectionServiceChanged(call, null, call.getConnectionService()); } - // Allow the ConnectionService to start the call in the active state. This case is helpful - // for conference calls or meetings that can skip the dialing stage. - if (callState == CallState.ACTIVE) { - setCallState(call, callState, "skipping the dialing state and setting active"); - } else { + if (mFeatureFlags.fixAudioFlickerForOutgoingCalls()) { + // Allow the ConnectionService to start the call in the active state. This case is + // helpful for conference calls or meetings that can skip the dialing stage. + if (callState == CallState.ACTIVE) { + setCallState(call, callState, "skipping the dialing state and setting active"); + } else { + markCallAsDialing(call); + } + } + else{ markCallAsDialing(call); } } @@ -1468,7 +1482,8 @@ public class CallsManager extends Call.ListenerBase false /* forceAttachToExistingConnection */, isConference, /* isConference */ mClockProxy, - mToastFactory); + mToastFactory, + mFeatureFlags); // 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 @@ -1495,7 +1510,10 @@ public class CallsManager extends Call.ListenerBase } } // Incoming address was set via EXTRA_INCOMING_CALL_ADDRESS above. - call.setAssociatedUser(phoneAccountHandle.getUserHandle()); + UserHandle associatedUser = UserUtil.getAssociatedUserForCall( + mFeatureFlags.workProfileAssociatedUser(), + getPhoneAccountRegistrar(), getCurrentUserHandle(), phoneAccountHandle); + call.setAssociatedUser(associatedUser); } if (phoneAccount != null) { @@ -1615,15 +1633,19 @@ public class CallsManager extends Call.ListenerBase // Check if the target phone account is possibly in ECBM. call.setIsInECBM(getEmergencyCallHelper() .isLastOutgoingEmergencyCallPAH(call.getTargetPhoneAccount())); - // If the phone account user profile is paused or the call isn't visible to the secondary/ - // guest user, reject the non-emergency incoming call. When the current user is the admin, - // we need to allow the calls to go through if the work profile isn't paused. We should - // always allow emergency calls and also allow non-emergency calls when ECBM is active for - // the phone account. - if ((mUserManager.isQuietModeEnabled(call.getAssociatedUser()) - || (!mUserManager.isUserAdmin(mCurrentUserHandle.getIdentifier()) - && !isCallVisibleForUser(call, mCurrentUserHandle))) - && !call.isEmergencyCall() && !call.isInECBM()) { + + // Check if call is visible to the current user. + boolean isCallHiddenFromProfile = !isCallVisibleForUser(call, mCurrentUserHandle); + // For admins, we should check if the work profile is paused in order to reject + // the call. + if (mUserManager.isUserAdmin(mCurrentUserHandle.getIdentifier())) { + isCallHiddenFromProfile &= mUserManager.isQuietModeEnabled( + call.getAssociatedUser()); + } + + // We should always allow emergency calls and also allow non-emergency calls when ECBM + // is active for the phone account. + if (isCallHiddenFromProfile && !call.isEmergencyCall() && !call.isInECBM()) { Log.d(TAG, "Rejecting non-emergency call because the owner %s is not running.", phoneAccountHandle.getUserHandle()); call.setMissedReason(USER_MISSED_NOT_RUNNING); @@ -1696,11 +1718,15 @@ public class CallsManager extends Call.ListenerBase true /* forceAttachToExistingConnection */, false, /* isConference */ mClockProxy, - mToastFactory); + mToastFactory, + mFeatureFlags); call.initAnalytics(); // For unknown calls, base the associated user off of the target phone account handle. - call.setAssociatedUser(phoneAccountHandle.getUserHandle()); + UserHandle associatedUser = UserUtil.getAssociatedUserForCall( + mFeatureFlags.workProfileAssociatedUser(), + getPhoneAccountRegistrar(), getCurrentUserHandle(), phoneAccountHandle); + call.setAssociatedUser(associatedUser); setIntentExtrasAndStartTime(call, extras); call.addListener(this); notifyStartCreateConnection(call); @@ -1814,7 +1840,8 @@ public class CallsManager extends Call.ListenerBase false /* forceAttachToExistingConnection */, isConference, /* isConference */ mClockProxy, - mToastFactory); + mToastFactory, + mFeatureFlags); if (extras.containsKey(TelecomManager.TRANSACTION_CALL_ID_KEY)) { call.setIsTransactionalCall(true); @@ -4221,7 +4248,8 @@ public class CallsManager extends Call.ListenerBase connectTime, connectElapsedTime, mClockProxy, - mToastFactory); + mToastFactory, + mFeatureFlags); // Unlike connections, conferences are not created first and then notified as create // connection complete from the CS. They originate from the CS and are reported directly to @@ -4239,7 +4267,10 @@ public class CallsManager extends Call.ListenerBase 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()); + UserHandle associatedUser = UserUtil.getAssociatedUserForCall( + mFeatureFlags.workProfileAssociatedUser(), getPhoneAccountRegistrar(), + getCurrentUserHandle(), phoneAccount); + call.setAssociatedUser(associatedUser); // 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(); @@ -5277,7 +5308,8 @@ public class CallsManager extends Call.ListenerBase connection.getConnectTimeMillis() /* connectTimeMillis */, connection.getConnectElapsedTimeMillis(), /* connectElapsedTimeMillis */ mClockProxy, - mToastFactory); + mToastFactory, + mFeatureFlags); call.initAnalytics(); call.getAnalytics().setCreatedFromExistingConnection(true); @@ -5292,7 +5324,10 @@ public class CallsManager extends Call.ListenerBase connection.getCallerDisplayNamePresentation()); // For existing connections, use the phone account user handle to determine the user // association with the call. - call.setAssociatedUser(connection.getPhoneAccount().getUserHandle()); + UserHandle associatedUser = UserUtil.getAssociatedUserForCall( + mFeatureFlags.workProfileAssociatedUser(), getPhoneAccountRegistrar(), + getCurrentUserHandle(), connection.getPhoneAccount()); + call.setAssociatedUser(associatedUser); call.addListener(this); call.putConnectionServiceExtras(connection.getExtras()); @@ -5937,7 +5972,7 @@ public class CallsManager extends Call.ListenerBase handoverFromCall.getHandle(), null, null, null, Call.CALL_DIRECTION_OUTGOING, false, - false, mClockProxy, mToastFactory); + false, mClockProxy, mToastFactory, mFeatureFlags); call.initAnalytics(); // Set self-managed and voipAudioMode if destination is self-managed CS @@ -6144,7 +6179,8 @@ public class CallsManager extends Call.ListenerBase false /* forceAttachToExistingConnection */, false, /* isConference */ mClockProxy, - mToastFactory); + mToastFactory, + mFeatureFlags); if (fromCall == null || isHandoverInProgress() || !isHandoverFromPhoneAccountSupported(fromCall.getTargetPhoneAccount()) || diff --git a/src/com/android/server/telecom/ConnectionServiceWrapper.java b/src/com/android/server/telecom/ConnectionServiceWrapper.java index c11ee6e33..07b048db5 100644 --- a/src/com/android/server/telecom/ConnectionServiceWrapper.java +++ b/src/com/android/server/telecom/ConnectionServiceWrapper.java @@ -525,8 +525,6 @@ public class ConnectionServiceWrapper extends ServiceBinder implements .validateAccountIconUserBoundary(icon, callingUserHandle)); } - if (ConnectionServiceWrapper.this.mIsRemoteConnectionService) return; - if (parcelableConference.getConnectElapsedTimeMillis() != 0 && mContext.checkCallingOrSelfPermission(MODIFY_PHONE_STATE) != PackageManager.PERMISSION_GRANTED) { @@ -941,9 +939,6 @@ public class ConnectionServiceWrapper extends ServiceBinder implements public void addExistingConnection(String callId, ParcelableConnection connection, Session.Info sessionInfo) { Log.startSession(sessionInfo, "CSW.aEC", mPackageAbbreviation); - - if (ConnectionServiceWrapper.this.mIsRemoteConnectionService) return; - UserHandle userHandle = Binder.getCallingUserHandle(); // Check that the Calling Package matches PhoneAccountHandle's Component Package PhoneAccountHandle callingPhoneAccountHandle = connection.getPhoneAccount(); @@ -1358,7 +1353,6 @@ public class ConnectionServiceWrapper extends ServiceBinder implements private final CallsManager mCallsManager; private final AppOpsManager mAppOpsManager; private final Context mContext; - public boolean mIsRemoteConnectionService = false; private ConnectionServiceFocusManager.ConnectionServiceFocusListener mConnSvrFocusListener; @@ -2548,13 +2542,13 @@ public class ConnectionServiceWrapper extends ServiceBinder implements private void logIncoming(String msg, Object... params) { // Keep these as debug; the incoming logging is traced on a package level through the // session logging. - Log.d(this, "CS -> TC[" + Log.getPackageAbbreviation(mComponentName) + "]:" - + " isRCS = " + this.mIsRemoteConnectionService + ": " + msg, params); + Log.d(this, "CS -> TC[" + Log.getPackageAbbreviation(mComponentName) + "]: " + + msg, params); } private void logOutgoing(String msg, Object... params) { - Log.d(this, "TC -> CS[" + Log.getPackageAbbreviation(mComponentName) + "]:" - + " isRCS = " + this.mIsRemoteConnectionService + ": " + msg, params); + Log.d(this, "TC -> CS[" + Log.getPackageAbbreviation(mComponentName) + "]: " + + msg, params); } private void queryRemoteConnectionServices(final UserHandle userHandle, @@ -2581,7 +2575,6 @@ public class ConnectionServiceWrapper extends ServiceBinder implements ConnectionServiceWrapper service = mConnectionServiceRepository.getService( handle.getComponentName(), handle.getUserHandle()); if (service != null && service != this) { - service.mIsRemoteConnectionService = true; simServices.add(service); } else { // This is unexpected, normally PhoneAccounts with CAPABILITY_CALL_PROVIDER are not diff --git a/src/com/android/server/telecom/InCallController.java b/src/com/android/server/telecom/InCallController.java index 184eaddec..1aee25c75 100644 --- a/src/com/android/server/telecom/InCallController.java +++ b/src/com/android/server/telecom/InCallController.java @@ -82,6 +82,7 @@ import java.util.UUID; import java.util.concurrent.CompletableFuture; import java.util.concurrent.TimeUnit; import java.util.stream.Collectors; +import java.util.stream.Stream; /** * Binds to {@link IInCallService} and provides the service to {@link CallsManager} through which it @@ -1406,17 +1407,31 @@ public class InCallController extends CallsManagerListenerBase implements @Override public void onCallRemoved(Call call) { Log.i(this, "onCallRemoved: %s", call); - if (mCallsManager.getCalls().isEmpty()) { + // Instead of checking if there are no active calls, we should check if there any calls with + // the same associated user returned from getUserFromCall. For instance, it's possible to + // have calls coexist on the personal profile and work profile, in which case, we would only + // remove the ICS connection for the user associated with the call to be disconnected. + UserHandle userFromCall = getUserFromCall(call); + Stream<Call> callsAssociatedWithUserFromCall = mCallsManager.getCalls().stream() + .filter((c) -> getUserFromCall(c).equals(userFromCall)); + boolean isCallCountZero = mFeatureFlags.workProfileAssociatedUser() + ? callsAssociatedWithUserFromCall.count() == 0 + : mCallsManager.getCalls().isEmpty(); + if (isCallCountZero) { /** Let's add a 2 second delay before we send unbind to the services to hopefully * give them enough time to process all the pending messages. */ mHandler.postDelayed(new Runnable("ICC.oCR", mLock) { @Override public void loggedRun() { - // Check again to make sure there are no active calls. - if (mCallsManager.getCalls().isEmpty()) { - unbindFromServices(getUserFromCall(call)); - + // Check again to make sure there are no active calls for the associated user. + Stream<Call> callsAssociatedWithUserFromCall = mCallsManager.getCalls().stream() + .filter((c) -> getUserFromCall(c).equals(userFromCall)); + boolean isCallCountZero = mFeatureFlags.workProfileAssociatedUser() + ? callsAssociatedWithUserFromCall.count() == 0 + : mCallsManager.getCalls().isEmpty(); + if (isCallCountZero) { + unbindFromServices(userFromCall); mEmergencyCallHelper.maybeRevokeTemporaryLocationPermission(); } } @@ -1832,6 +1847,7 @@ public class InCallController extends CallsManagerListenerBase implements * Unbinds an existing bound connection to the in-call app. */ public void unbindFromServices(UserHandle userHandle) { + Log.i(this, "Unbinding from services for user %s", userHandle); try { mContext.unregisterReceiver(mPackageChangedReceiver); } catch (IllegalArgumentException e) { @@ -2320,7 +2336,9 @@ public class InCallController extends CallsManagerListenerBase implements } // Upon successful connection, send the state of the world to the service. - List<Call> calls = orderCallsWithChildrenFirst(mCallsManager.getCalls()); + List<Call> calls = orderCallsWithChildrenFirst(mCallsManager.getCalls().stream().filter( + call -> getUserFromCall(call).equals(userHandle)) + .collect(Collectors.toUnmodifiableList())); Log.i(this, "Adding %s calls to InCallService after onConnected: %s, including external " + "calls", calls.size(), info.getComponentName()); int numCallsSent = 0; @@ -2463,6 +2481,9 @@ public class InCallController extends CallsManagerListenerBase implements } } Log.i(this, "Components updated: %s", componentsUpdated); + } else { + Log.i(this, + "Unable to update call. InCallService not found for user: %s", userFromCall); } } @@ -2901,8 +2922,11 @@ public class InCallController extends CallsManagerListenerBase implements } else { UserHandle userFromCall = call.getAssociatedUser(); UserManager userManager = mContext.getSystemService(UserManager.class); - // Emergency call should never be blocked, so if the user associated with call is in - // quite mode, use the primary user for the emergency call. + // Emergency call should never be blocked, so if the user associated with the target + // phone account handle user is in quiet mode, use the current user for the ecall. + // Note, that this only applies to incoming calls that are received on assigned + // sims (i.e. work sim), where the associated user would be the target phone account + // handle user. if ((call.isEmergencyCall() || call.isInECBM()) && (userManager.isQuietModeEnabled(userFromCall) // We should also account for secondary/guest users where the profile may not diff --git a/src/com/android/server/telecom/UserUtil.java b/src/com/android/server/telecom/UserUtil.java index d0a561ad9..670ad3438 100644 --- a/src/com/android/server/telecom/UserUtil.java +++ b/src/com/android/server/telecom/UserUtil.java @@ -24,8 +24,11 @@ import android.net.Uri; import android.os.UserHandle; import android.os.UserManager; import android.telecom.Log; +import android.telecom.PhoneAccount; +import android.telecom.PhoneAccountHandle; import com.android.server.telecom.components.ErrorDialogActivity; +import com.android.server.telecom.flags.FeatureFlags; public final class UserUtil { @@ -99,4 +102,37 @@ public final class UserUtil { } return false; } + + /** + * Gets the associated user for the given call. Note: this is applicable to all calls except + * outgoing calls as the associated user is already based off of the user placing the + * call. + * + * @param phoneAccountRegistrar + * @param currentUser Current user profile (this can either be the admin or a secondary/guest + * user). Note that work profile users fall under the admin user. + * @param targetPhoneAccount The phone account to retrieve the {@link UserHandle} from. + * @return current user if it isn't the admin or if the work profile is paused for the target + * phone account handle user, otherwise return the target phone account handle user. If the + * flag is disabled, return the legacy {@link UserHandle}. + */ + public static UserHandle getAssociatedUserForCall(boolean isAssociatedUserFlagEnabled, + PhoneAccountRegistrar phoneAccountRegistrar, UserHandle currentUser, + PhoneAccountHandle targetPhoneAccount) { + if (!isAssociatedUserFlagEnabled) { + return targetPhoneAccount.getUserHandle(); + } + // For multi-user phone accounts, associate the call with the profile receiving/placing + // the call. For SIM accounts (that are assigned to specific users), the user association + // will be placed on the target phone account handle user. + PhoneAccount account = phoneAccountRegistrar.getPhoneAccountUnchecked(targetPhoneAccount); + if (account != null) { + return account.hasCapabilities(PhoneAccount.CAPABILITY_MULTI_USER) + ? currentUser + : targetPhoneAccount.getUserHandle(); + } + // If target phone account handle is null or account cannot be found, + // return the current user. + return currentUser; + } } diff --git a/src/com/android/server/telecom/bluetooth/BluetoothDeviceManager.java b/src/com/android/server/telecom/bluetooth/BluetoothDeviceManager.java index c5e56b377..9ae58b33d 100644 --- a/src/com/android/server/telecom/bluetooth/BluetoothDeviceManager.java +++ b/src/com/android/server/telecom/bluetooth/BluetoothDeviceManager.java @@ -740,9 +740,7 @@ public class BluetoothDeviceManager { } public boolean isInbandRingingEnabled() { - // Get the inband ringing enabled status of expected BT device to route call audio instead - // of using the address of currently connected device. - BluetoothDevice activeDevice = mBluetoothRouteManager.getMostRecentlyReportedActiveDevice(); + BluetoothDevice activeDevice = mBluetoothRouteManager.getBluetoothAudioConnectedDevice(); Log.i(this, "isInbandRingingEnabled: activeDevice: " + activeDevice); if (mBluetoothRouteManager.isCachedLeAudioDevice(activeDevice)) { if (mBluetoothLeAudioService == null) { diff --git a/src/com/android/server/telecom/bluetooth/BluetoothRouteManager.java b/src/com/android/server/telecom/bluetooth/BluetoothRouteManager.java index 6cf6ae432..644d9aeda 100644 --- a/src/com/android/server/telecom/bluetooth/BluetoothRouteManager.java +++ b/src/com/android/server/telecom/bluetooth/BluetoothRouteManager.java @@ -393,8 +393,13 @@ public class BluetoothRouteManager extends StateMachine { String actualAddress = connectBtAudio(address, true /* switchingBtDevices*/); if (actualAddress != null) { - transitionTo(getConnectingStateForAddress(address, - "AudioConnected/CONNECT_BT")); + if (mFeatureFlags.useActualAddressToEnterConnectingState()) { + transitionTo(getConnectingStateForAddress(actualAddress, + "AudioConnected/CONNECT_BT")); + } else { + transitionTo(getConnectingStateForAddress(address, + "AudioConnected/CONNECT_BT")); + } } else { Log.w(LOG_TAG, "Tried to connect to %s but failed" + " to connect to any BT device.", (String) args.arg2); @@ -663,10 +668,6 @@ public class BluetoothRouteManager extends StateMachine { } } - public BluetoothDevice getMostRecentlyReportedActiveDevice() { - return mMostRecentlyReportedActiveDevice; - } - public boolean hasBtActiveDevice() { return mLeAudioActiveDeviceCache != null || mHearingAidActiveDeviceCache != null || |