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

Commit 9c470141 authored by Chinmay Dhodapkar's avatar Chinmay Dhodapkar Committed by Automerger Merge Worker
Browse files

Merge "Fix component query/binding for multiuser" into udc-dev am: 6ade6d1d am: 4b7f39d6

parents f8656161 4b7f39d6
Loading
Loading
Loading
Loading
+299 −37
Original line number Original line Diff line number Diff line
@@ -47,6 +47,7 @@ import android.os.RemoteException;
import android.os.Trace;
import android.os.Trace;
import android.os.UserHandle;
import android.os.UserHandle;
import android.os.UserManager;
import android.os.UserManager;
import android.permission.PermissionManager;
import android.telecom.CallAudioState;
import android.telecom.CallAudioState;
import android.telecom.CallEndpoint;
import android.telecom.CallEndpoint;
import android.telecom.ConnectionService;
import android.telecom.ConnectionService;
@@ -146,16 +147,20 @@ public class InCallController extends CallsManagerListenerBase implements
        private long mBindingStartTime;
        private long mBindingStartTime;
        private long mDisconnectTime;
        private long mDisconnectTime;


        private boolean mHasCrossUserOrProfilePerm;

        public InCallServiceInfo(ComponentName componentName,
        public InCallServiceInfo(ComponentName componentName,
                boolean isExternalCallsSupported,
                boolean isExternalCallsSupported,
                boolean isSelfManageCallsSupported,
                boolean isSelfManageCallsSupported,
                int type) {
                int type, boolean hasCrossUserOrProfilePerm) {
            mComponentName = componentName;
            mComponentName = componentName;
            mIsExternalCallsSupported = isExternalCallsSupported;
            mIsExternalCallsSupported = isExternalCallsSupported;
            mIsSelfManagedCallsSupported = isSelfManageCallsSupported;
            mIsSelfManagedCallsSupported = isSelfManageCallsSupported;
            mType = type;
            mType = type;
            mHasCrossUserOrProfilePerm = hasCrossUserOrProfilePerm;
        }
        }


        public boolean hasCrossUserOrProfilePermission() { return mHasCrossUserOrProfilePerm; }
        public ComponentName getComponentName() {
        public ComponentName getComponentName() {
            return mComponentName;
            return mComponentName;
        }
        }
@@ -292,8 +297,19 @@ public class InCallController extends CallsManagerListenerBase implements
        private boolean mIsNullBinding = false;
        private boolean mIsNullBinding = false;
        private NotificationManager mNotificationManager;
        private NotificationManager mNotificationManager;


        //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;

        public InCallServiceBindingConnection(InCallServiceInfo info) {
        public InCallServiceBindingConnection(InCallServiceInfo info) {
            mInCallServiceInfo = info;
            mInCallServiceInfo = info;
            mUserHandleToUseForBinding = null;
        }

        public InCallServiceBindingConnection(InCallServiceInfo info,
                UserHandle userHandleToUseForBinding) {
            mInCallServiceInfo = info;
            mUserHandleToUseForBinding = userHandleToUseForBinding;
        }
        }


        @Override
        @Override
@@ -335,14 +351,31 @@ public class InCallController extends CallsManagerListenerBase implements
            Log.i(this, "Attempting to bind to InCall %s, with %s", mInCallServiceInfo, intent);
            Log.i(this, "Attempting to bind to InCall %s, with %s", mInCallServiceInfo, intent);
            mIsConnected = true;
            mIsConnected = true;
            mInCallServiceInfo.setBindingStartTime(mClockProxy.elapsedRealtime());
            mInCallServiceInfo.setBindingStartTime(mClockProxy.elapsedRealtime());
            UserHandle userToBind = getUserFromCall(call);
            boolean isManagedProfile = UserUtil.isManagedProfile(mContext, userFromCall);
            boolean isManagedProfile = UserUtil.isManagedProfile(mContext, userToBind);
            // Note that UserHandle.CURRENT fails to capture the work profile, so we need to handle
            // Note that UserHandle.CURRENT fails to capture the work profile, so we need to handle
            // it separately to ensure that the ICS is bound to the appropriate user. If ECBM is
            // it separately to ensure that the ICS is bound to the appropriate user. If ECBM is
            // active, we know that a work sim was previously used to place a MO emergency call. We
            // active, we know that a work sim was previously used to place a MO emergency call. We
            // need to ensure that we bind to the CURRENT_USER in this case, as the work user would
            // need to ensure that we bind to the CURRENT_USER in this case, as the work user would
            // not be running (handled in getUserFromCall).
            // not be running (handled in getUserFromCall).
            userToBind = isManagedProfile ? userToBind : UserHandle.CURRENT;
            UserHandle userToBind = isManagedProfile ? userFromCall : UserHandle.CURRENT;
            if ((mInCallServiceInfo.mType == IN_CALL_SERVICE_TYPE_NON_UI
                    || mInCallServiceInfo.mType == IN_CALL_SERVICE_TYPE_CAR_MODE_UI) && (
                    mUserHandleToUseForBinding != null)) {
                //guarding change for non-UI/carmode-UI services which may not be present for
                // work profile.
                //In this case, we use the parent user handle. (This also seems to be more
                // accurate that USER_CURRENT since we queried/discovered the packages using the
                // parent handle)
                if (mInCallServiceInfo.hasCrossUserOrProfilePermission()) {
                    userToBind = mUserHandleToUseForBinding;
                } else {
                    Log.i(this,
                            "service does not have INTERACT_ACROSS_PROFILES or "
                                    + "INTERACT_ACROSS_USERS permission");
                }
            }
            Log.i(this, "using user id: %s for binding. User from Call is: %s", userToBind,
                    userFromCall);
            if (!mContext.bindServiceAsUser(intent, mServiceConnection,
            if (!mContext.bindServiceAsUser(intent, mServiceConnection,
                    Context.BIND_AUTO_CREATE | Context.BIND_FOREGROUND_SERVICE
                    Context.BIND_AUTO_CREATE | Context.BIND_FOREGROUND_SERVICE
                        | Context.BIND_ALLOW_BACKGROUND_ACTIVITY_STARTS
                        | Context.BIND_ALLOW_BACKGROUND_ACTIVITY_STARTS
@@ -668,7 +701,7 @@ public class InCallController extends CallsManagerListenerBase implements
                }
                }


                mCarModeConnection = mCurrentConnection =
                mCarModeConnection = mCurrentConnection =
                        new InCallServiceBindingConnection(carModeConnectionInfo);
                        new InCallServiceBindingConnection(carModeConnectionInfo, userHandle);
                mIsCarMode = true;
                mIsCarMode = true;


                int result = mCurrentConnection.connect(null);
                int result = mCurrentConnection.connect(null);
@@ -960,17 +993,28 @@ public class InCallController extends CallsManagerListenerBase implements
        }
        }
    };
    };


    private UserHandle findChildManagedProfileUser(UserHandle parent, UserManager um) {
        UserHandle childManagedProfileUser = null;

        //find child managed profile user (if any)
        List<UserHandle> allUsers = um.getAllProfiles();
        for (UserHandle u : allUsers) {
            if ((um.getProfileParent(u) != null) && (um.getProfileParent(u).equals(parent))
                    && um.isManagedProfile(u.getIdentifier())) {
                //found managed profile child
                Log.i(this,
                        "Child managed profile user found: " + u.getIdentifier());
                childManagedProfileUser = u;
                break;
            }
        }
        return childManagedProfileUser;
    }
    private BroadcastReceiver mPackageChangedReceiver = new BroadcastReceiver() {
    private BroadcastReceiver mPackageChangedReceiver = new BroadcastReceiver() {
        @Override
        private List<InCallController.InCallServiceInfo> getNonUiInCallServiceInfoList(
        public void onReceive(Context context, Intent intent) {
                Intent intent, UserHandle userHandle) {
            Log.startSession("ICC.pCR");
            try {
                if (Intent.ACTION_PACKAGE_CHANGED.equals(intent.getAction())) {
                    synchronized (mLock) {
            String changedPackage = intent.getData().getSchemeSpecificPart();
            String changedPackage = intent.getData().getSchemeSpecificPart();
                        int uid = intent.getIntExtra(Intent.EXTRA_UID, 0);
            List<InCallController.InCallServiceInfo> inCallServiceInfoList =
                        UserHandle userHandle = UserHandle.getUserHandleForUid(uid);
                        List<InCallServiceBindingConnection> componentsToBind =
                    Arrays.stream(intent.getStringArrayExtra(
                    Arrays.stream(intent.getStringArrayExtra(
                                    Intent.EXTRA_CHANGED_COMPONENT_NAME_LIST))
                                    Intent.EXTRA_CHANGED_COMPONENT_NAME_LIST))
                            .map((className) ->
                            .map((className) ->
@@ -980,14 +1024,106 @@ public class InCallController extends CallsManagerListenerBase implements
                            .flatMap(componentName -> getInCallServiceComponents(
                            .flatMap(componentName -> getInCallServiceComponents(
                                    userHandle, componentName,
                                    userHandle, componentName,
                                    IN_CALL_SERVICE_TYPE_NON_UI).stream())
                                    IN_CALL_SERVICE_TYPE_NON_UI).stream())
                                        .map(InCallServiceBindingConnection::new)
                            .collect(Collectors.toList());
                            .collect(Collectors.toList());
            return ((inCallServiceInfoList != null) ? inCallServiceInfoList : new ArrayList<>());
        }


                        if (mNonUIInCallServiceConnections.containsKey(userHandle)) {
        //Here we query components using the userHandle. We then also query components using the
                            mNonUIInCallServiceConnections.get(userHandle).
        //parent userHandle (if any) while removing duplicates. For non-dup components found using
                                    addConnections(componentsToBind);
        //parent userHandle, we use the overloaded InCallServiceBindingConnection constructor.
        @SuppressWarnings("ReturnValueIgnored")
        private List<InCallServiceBindingConnection> getNonUiInCallServiceBindingConnectionList(
                Intent intent, @NonNull UserHandle userHandle, UserHandle parentUserHandle) {
            List<InCallServiceBindingConnection> result = new ArrayList<>();
            List<InCallController.InCallServiceInfo> serviceInfoListForParent = new ArrayList<>();

            //query and add components for the child
            List<InCallController.InCallServiceInfo> serviceInfoListForUser =
                    getNonUiInCallServiceInfoList(intent, userHandle);

            //if user has a parent, get components for parents
            if (parentUserHandle != null) {
                serviceInfoListForParent = getNonUiInCallServiceInfoList(intent, parentUserHandle);
            }

            serviceInfoListForUser
                    .stream()
                    .map(InCallServiceBindingConnection::new)
                    .collect(Collectors.toCollection(() -> result));

            serviceInfoListForParent
                    .stream()
                    .filter((e) -> !(serviceInfoListForUser.contains(e)))
                    .map((serviceinfo) -> new InCallServiceBindingConnection(serviceinfo,
                            parentUserHandle))
                    .collect(Collectors.toCollection(() -> result));

            return result;
        }
        }


        @Override
        public void onReceive(Context context, Intent intent) {
            Log.startSession("ICC.pCR");
            UserManager um = mContext.getSystemService(UserManager.class);
            try {
                if (Intent.ACTION_PACKAGE_CHANGED.equals(intent.getAction())) {
                    synchronized (mLock) {
                        int uid = intent.getIntExtra(Intent.EXTRA_UID, 0);
                        UserHandle userHandle = UserHandle.getUserHandleForUid(uid);
                        boolean isManagedProfile = um.isManagedProfile(userHandle.getIdentifier());

                        /*
                        There are two possibilities here:
                         1) We get a work-profile/managed userHandle. In this case we need to check
                         if there are any ongoing calls for that user. If yes, then process further
                         by querying component using this user handle (also bindAsUser using this
                          handle). Else safely ignore it.
                                OR
                         2) We get the primary/non-managed userHandle. In this case, we have two
                          sub-cases to handle:
                                   a) If there are ongoing calls for this user, query components
                                   using this user and addConnections
                                   b) If there are ongoing calls for the child of this user, we
                                   also addConnections to that child (but invoke bindAsUser later
                                    with the parent handle).

                         */

                        UserHandle childManagedProfileUser = findChildManagedProfileUser(
                                userHandle, um);
                        boolean isUserKeyPresent = mNonUIInCallServiceConnections.containsKey(
                                userHandle);
                        boolean isChildUserKeyPresent = (childManagedProfileUser == null) ? false
                                : mNonUIInCallServiceConnections.containsKey(
                                        childManagedProfileUser);
                        List<InCallServiceBindingConnection> componentsToBindForUser = null;
                        List<InCallServiceBindingConnection> componentsToBindForChild = null;

                        if(isUserKeyPresent) {
                            componentsToBindForUser =
                                    getNonUiInCallServiceBindingConnectionList(intent,
                                            userHandle, null);
                        }
                        if (isChildUserKeyPresent) {
                            componentsToBindForChild =
                                    getNonUiInCallServiceBindingConnectionList(intent,
                                            childManagedProfileUser, userHandle);
                        }

                        Log.i(this,
                                "isUserKeyPresent:%b isChildKeyPresent:%b isManagedProfile:%b "
                                        + "user:%d",
                                isUserKeyPresent, isChildUserKeyPresent, isManagedProfile,
                                userHandle.getIdentifier());

                        if (isUserKeyPresent && componentsToBindForUser != null) {
                            mNonUIInCallServiceConnections.get(userHandle).
                                    addConnections(componentsToBindForUser);
                        }
                        if (isChildUserKeyPresent && componentsToBindForChild != null) {
                            mNonUIInCallServiceConnections.get(childManagedProfileUser).
                                    addConnections(componentsToBindForChild);
                        }
                        // If the current car mode app become enabled from disabled, update
                        // If the current car mode app become enabled from disabled, update
                        // the connection to binding
                        // the connection to binding
                        updateCarModeForConnections();
                        updateCarModeForConnections();
@@ -1691,6 +1827,14 @@ public class InCallController extends CallsManagerListenerBase implements
    @VisibleForTesting
    @VisibleForTesting
    public void bindToServices(Call call) {
    public void bindToServices(Call call) {
        UserHandle userFromCall = getUserFromCall(call);
        UserHandle userFromCall = getUserFromCall(call);
        UserHandle parentUser = null;
        UserManager um = mContext.getSystemService(UserManager.class);

        if (um.isManagedProfile(userFromCall.getIdentifier())) {
            parentUser = um.getProfileParent(userFromCall);
            Log.i(this, "child:%s  parent:%s", userFromCall, parentUser);
        }

        if (!mInCallServiceConnections.containsKey(userFromCall)) {
        if (!mInCallServiceConnections.containsKey(userFromCall)) {
            InCallServiceConnection dialerInCall = null;
            InCallServiceConnection dialerInCall = null;
            InCallServiceInfo defaultDialerComponentInfo = getDefaultDialerComponent(userFromCall);
            InCallServiceInfo defaultDialerComponentInfo = getDefaultDialerComponent(userFromCall);
@@ -1710,10 +1854,24 @@ public class InCallController extends CallsManagerListenerBase implements


            InCallServiceConnection carModeInCall = null;
            InCallServiceConnection carModeInCall = null;
            InCallServiceInfo carModeComponentInfo = getCurrentCarModeComponent(userFromCall);
            InCallServiceInfo carModeComponentInfo = getCurrentCarModeComponent(userFromCall);
            InCallServiceInfo carModeComponentInfoForParentUser = null;
            if(parentUser != null) {
                //query using parent user too
                carModeComponentInfoForParentUser = getCurrentCarModeComponent(
                        parentUser);
            }

            if (carModeComponentInfo != null &&
            if (carModeComponentInfo != null &&
                    !carModeComponentInfo.getComponentName().equals(
                    !carModeComponentInfo.getComponentName().equals(
                            mDefaultDialerCache.getSystemDialerComponent())) {
                            mDefaultDialerCache.getSystemDialerComponent())) {
                carModeInCall = new InCallServiceBindingConnection(carModeComponentInfo);
                carModeInCall = new InCallServiceBindingConnection(carModeComponentInfo);
            } else if (carModeComponentInfo == null &&
                    carModeComponentInfoForParentUser != null &&
                    !carModeComponentInfoForParentUser.getComponentName().equals(
                            mDefaultDialerCache.getSystemDialerComponent())) {
                carModeInCall = new InCallServiceBindingConnection(
                        carModeComponentInfoForParentUser, parentUser);
                Log.i(this, "Using car mode component queried using parent handle");
            }
            }


            mInCallServiceConnections.put(userFromCall,
            mInCallServiceConnections.put(userFromCall,
@@ -1747,12 +1905,43 @@ public class InCallController extends CallsManagerListenerBase implements


    private void updateNonUiInCallServices(Call call) {
    private void updateNonUiInCallServices(Call call) {
        UserHandle userFromCall = getUserFromCall(call);
        UserHandle userFromCall = getUserFromCall(call);
        UserHandle parentUser = null;

        UserManager um = mContext.getSystemService(UserManager.class);
        if(um.isManagedProfile(userFromCall.getIdentifier()))
        {
            parentUser = um.getProfileParent(userFromCall);
        }

        List<InCallServiceInfo> nonUIInCallComponents =
        List<InCallServiceInfo> nonUIInCallComponents =
                getInCallServiceComponents(userFromCall, IN_CALL_SERVICE_TYPE_NON_UI);
                getInCallServiceComponents(userFromCall, IN_CALL_SERVICE_TYPE_NON_UI);
        List<InCallServiceInfo> nonUIInCallComponentsForParent = new ArrayList<>();
        if(parentUser != null)
        {
            //also get Non-UI services using parent handle.
            nonUIInCallComponentsForParent =
                    getInCallServiceComponents(parentUser, IN_CALL_SERVICE_TYPE_NON_UI);

        }
        List<InCallServiceBindingConnection> nonUIInCalls = new LinkedList<>();
        List<InCallServiceBindingConnection> nonUIInCalls = new LinkedList<>();
        for (InCallServiceInfo serviceInfo : nonUIInCallComponents) {
        for (InCallServiceInfo serviceInfo : nonUIInCallComponents) {
            nonUIInCalls.add(new InCallServiceBindingConnection(serviceInfo));
            nonUIInCalls.add(new InCallServiceBindingConnection(serviceInfo));
        }
        }

        //add nonUI InCall services queried using parent user (if any)
        for (InCallServiceInfo serviceInfo : nonUIInCallComponentsForParent) {
            if (nonUIInCallComponents.contains(serviceInfo)) {
                //skip dups
                Log.i(this, "skipped duplicate component found using parent user: "
                        + serviceInfo.getComponentName());
            } else {
                nonUIInCalls.add(new InCallServiceBindingConnection(serviceInfo, parentUser));
                Log.i(this,
                        "added component queried using parent user: "
                                + serviceInfo.getComponentName());
            }
        }

        List<String> callCompanionApps = mCallsManager
        List<String> callCompanionApps = mCallsManager
                .getRoleManagerAdapter().getCallCompanionApps();
                .getRoleManagerAdapter().getCallCompanionApps();
        if (callCompanionApps != null && !callCompanionApps.isEmpty()) {
        if (callCompanionApps != null && !callCompanionApps.isEmpty()) {
@@ -1819,7 +2008,7 @@ public class InCallController extends CallsManagerListenerBase implements
            // Last Resort: Try to bind to the ComponentName given directly.
            // Last Resort: Try to bind to the ComponentName given directly.
            Log.e(this, new Exception(), "Package Manager could not find ComponentName: "
            Log.e(this, new Exception(), "Package Manager could not find ComponentName: "
                    + componentName + ". Trying to bind anyway.");
                    + componentName + ". Trying to bind anyway.");
            return new InCallServiceInfo(componentName, false, false, type);
            return new InCallServiceInfo(componentName, false, false, type, false);
        }
        }
    }
    }


@@ -1854,6 +2043,34 @@ public class InCallController extends CallsManagerListenerBase implements
        return getInCallServiceComponents(userHandle, packageName,
        return getInCallServiceComponents(userHandle, packageName,
                componentName, requestedType, true /* ignoreDisabled */);
                componentName, requestedType, true /* ignoreDisabled */);
    }
    }
    private boolean canInteractAcrossUsersOrProfiles(ServiceInfo serviceInfo,
            PackageManager packageManager) {
        String op = AppOpsManager.permissionToOp("android.permission.INTERACT_ACROSS_PROFILES");
        String[] uidPackages = packageManager.getPackagesForUid(serviceInfo.applicationInfo.uid);

        boolean hasInteractAcrossProfiles = Arrays.stream(uidPackages).anyMatch(
                p -> ((packageManager.checkPermission(
                        Manifest.permission.INTERACT_ACROSS_PROFILES,
                        p) == PackageManager.PERMISSION_GRANTED)
                ));
        boolean hasInteractAcrossUsers = Arrays.stream(uidPackages).anyMatch(
                p -> ((packageManager.checkPermission(
                        Manifest.permission.INTERACT_ACROSS_USERS,
                        p) == PackageManager.PERMISSION_GRANTED)
                ));
        boolean hasInteractAcrossProfilesAppOp = Arrays.stream(uidPackages).anyMatch(
                p -> (AppOpsManager.MODE_ALLOWED == mAppOpsManager.checkOpNoThrow(
                        op, serviceInfo.applicationInfo.uid, p))
        );
        Log.i(this,
                "packageName:%s INTERACT_ACROSS_USERS:%b INTERACT_ACROSS_PROFILES:%b "
                        + "INTERACT_ACROSS_PROFILES_APPOP:%b",
                uidPackages[0], hasInteractAcrossUsers, hasInteractAcrossProfiles,
                hasInteractAcrossProfilesAppOp);

        return (hasInteractAcrossUsers || hasInteractAcrossProfiles
                || hasInteractAcrossProfilesAppOp);
    }


    private List<InCallServiceInfo> getInCallServiceComponents(UserHandle userHandle,
    private List<InCallServiceInfo> getInCallServiceComponents(UserHandle userHandle,
            String packageName, ComponentName componentName,
            String packageName, ComponentName componentName,
@@ -1867,11 +2084,16 @@ public class InCallController extends CallsManagerListenerBase implements
        if (componentName != null) {
        if (componentName != null) {
            serviceIntent.setComponent(componentName);
            serviceIntent.setComponent(componentName);
        }
        }
        Log.i(this,
                "getComponents, pkgname: " + packageName + " comp: " + componentName + " userid: "
                        + userHandle.getIdentifier() + " requestedType: " + requestedType);
        PackageManager packageManager = mContext.getPackageManager();
        PackageManager packageManager = mContext.getPackageManager();
        Context userContext = mContext.createContextAsUser(userHandle,
        Context userContext = mContext.createContextAsUser(userHandle,
                0 /* flags */);
                0 /* flags */);
        PackageManager userPackageManager = userContext != null ?
        PackageManager userPackageManager = userContext != null ?
                userContext.getPackageManager() : packageManager;
                userContext.getPackageManager() : packageManager;


        for (ResolveInfo entry : packageManager.queryIntentServicesAsUser(
        for (ResolveInfo entry : packageManager.queryIntentServicesAsUser(
                serviceIntent,
                serviceIntent,
                PackageManager.GET_META_DATA | PackageManager.MATCH_DISABLED_COMPONENTS,
                PackageManager.GET_META_DATA | PackageManager.MATCH_DISABLED_COMPONENTS,
@@ -1888,6 +2110,10 @@ public class InCallController extends CallsManagerListenerBase implements


                int currentType = getInCallServiceType(userHandle,
                int currentType = getInCallServiceType(userHandle,
                        entry.serviceInfo, packageManager, packageName);
                        entry.serviceInfo, packageManager, packageName);

                boolean hasInteractAcrossUserOrProfilePerm = canInteractAcrossUsersOrProfiles(
                        entry.serviceInfo, packageManager);

                ComponentName foundComponentName =
                ComponentName foundComponentName =
                        new ComponentName(serviceInfo.packageName, serviceInfo.name);
                        new ComponentName(serviceInfo.packageName, serviceInfo.name);
                if (requestedType == IN_CALL_SERVICE_TYPE_NON_UI) {
                if (requestedType == IN_CALL_SERVICE_TYPE_NON_UI) {
@@ -1903,9 +2129,16 @@ public class InCallController extends CallsManagerListenerBase implements
                    isRequestedType = requestedType == currentType;
                    isRequestedType = requestedType == currentType;
                }
                }


                Log.i(this,
                        "found:%s isRequestedtype:%b isEnabled:%b ignoreDisabled:%b "
                                + "hasCrossProfilePerm:%b",
                        foundComponentName, isRequestedType, isEnabled, ignoreDisabled,
                        hasInteractAcrossUserOrProfilePerm);

                if ((!ignoreDisabled || isEnabled) && isRequestedType) {
                if ((!ignoreDisabled || isEnabled) && isRequestedType) {
                    retval.add(new InCallServiceInfo(foundComponentName, isExternalCallsSupported,
                    retval.add(new InCallServiceInfo(foundComponentName, isExternalCallsSupported,
                            isSelfManageCallsSupported, requestedType));
                            isSelfManageCallsSupported, requestedType,
                            hasInteractAcrossUserOrProfilePerm));
                }
                }
            }
            }
        }
        }
@@ -2439,19 +2672,48 @@ public class InCallController extends CallsManagerListenerBase implements
        Log.i(this, "updateCarModeForConnections: car mode apps: %s",
        Log.i(this, "updateCarModeForConnections: car mode apps: %s",
                mCarModeTracker.getCarModeApps().stream().collect(Collectors.joining(", ")));
                mCarModeTracker.getCarModeApps().stream().collect(Collectors.joining(", ")));


        if (mInCallServiceConnections.containsKey(mCallsManager.getCurrentUserHandle())) {
        UserManager um = mContext.getSystemService(UserManager.class);
            CarSwappingInCallServiceConnection inCallServiceConnection = mInCallServiceConnections.
        UserHandle currentUser = mCallsManager.getCurrentUserHandle();
                    get(mCallsManager.getCurrentUserHandle());
        UserHandle childUser = findChildManagedProfileUser(currentUser, um);

        CarSwappingInCallServiceConnection inCallServiceConnectionForCurrentUser = null;
        CarSwappingInCallServiceConnection inCallServiceConnectionForChildUser = null;

        Log.i(this, "update carmode current:%s parent:%s", currentUser, childUser);
        if (mInCallServiceConnections.containsKey(currentUser)) {
            inCallServiceConnectionForCurrentUser = mInCallServiceConnections.
                    get(currentUser);
        }
        if (childUser != null && mInCallServiceConnections.containsKey(childUser)) {
            inCallServiceConnectionForChildUser = mInCallServiceConnections.
                    get(childUser);
        }

        if (shouldUseCarModeUI()) {
        if (shouldUseCarModeUI()) {
            Log.i(this, "updateCarModeForConnections: potentially update car mode app.");
            Log.i(this, "updateCarModeForConnections: potentially update car mode app.");
                inCallServiceConnection.changeCarModeApp(mCarModeTracker.getCurrentCarModePackage(),
            //always pass current user to changeCarMode. That will ultimately be used for bindAsUser
                        mCallsManager.getCurrentUserHandle());
            if (inCallServiceConnectionForCurrentUser != null) {
                inCallServiceConnectionForCurrentUser.changeCarModeApp(
                        mCarModeTracker.getCurrentCarModePackage(),
                        currentUser);
            }
            if (inCallServiceConnectionForChildUser != null) {
                inCallServiceConnectionForChildUser.changeCarModeApp(
                        mCarModeTracker.getCurrentCarModePackage(),
                        currentUser);
            }
        } else {
        } else {
                if (inCallServiceConnection.isCarMode()) {
            if (inCallServiceConnectionForCurrentUser != null
                    && inCallServiceConnectionForCurrentUser.isCarMode()) {
                Log.i(this, "updateCarModeForConnections: car mode no longer "
                Log.i(this, "updateCarModeForConnections: car mode no longer "
                            + "applicable; disabling");
                        + "applicable for current user; disabling");
                    inCallServiceConnection.disableCarMode();
                inCallServiceConnectionForCurrentUser.disableCarMode();
            }
            }
            if (inCallServiceConnectionForChildUser != null
                    && inCallServiceConnectionForChildUser.isCarMode()) {
                Log.i(this, "updateCarModeForConnections: car mode no longer "
                        + "applicable for child user; disabling");
                inCallServiceConnectionForChildUser.disableCarMode();
            }
            }
        }
        }
    }
    }
+71 −0

File changed.

Preview size limit exceeded, changes collapsed.