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

Commit 48e7cd6b authored by Treehugger Robot's avatar Treehugger Robot Committed by Automerger Merge Worker
Browse files

Merge "BT changes for preferred audio profile interactions with the audio...

Merge "BT changes for preferred audio profile interactions with the audio framework" am: 10e396c9 am: eca2ed37

Original change: https://android-review.googlesource.com/c/platform/packages/modules/Bluetooth/+/2376519



Change-Id: I7fa08b6edfbad540fa436152c655e800fae2ca2e
Signed-off-by: default avatarAutomerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
parents 0af4cd99 eca2ed37
Loading
Loading
Loading
Loading
+259 −42
Original line number Original line Diff line number Diff line
@@ -180,6 +180,7 @@ public class AdapterService extends Service {
    private static final int MIN_OFFLOADED_SCAN_STORAGE_BYTES = 1024;
    private static final int MIN_OFFLOADED_SCAN_STORAGE_BYTES = 1024;
    private static final Duration PENDING_SOCKET_HANDOFF_TIMEOUT = Duration.ofMinutes(1);
    private static final Duration PENDING_SOCKET_HANDOFF_TIMEOUT = Duration.ofMinutes(1);
    private static final Duration GENERATE_LOCAL_OOB_DATA_TIMEOUT = Duration.ofSeconds(2);
    private static final Duration GENERATE_LOCAL_OOB_DATA_TIMEOUT = Duration.ofSeconds(2);
    private static final Duration PREFERRED_AUDIO_PROFILE_CHANGE_TIMEOUT = Duration.ofSeconds(10);


    private final Object mEnergyInfoLock = new Object();
    private final Object mEnergyInfoLock = new Object();
    private int mStackReportedState;
    private int mStackReportedState;
@@ -306,7 +307,9 @@ public class AdapterService extends Service {
            mPreferredAudioProfilesCallbacks;
            mPreferredAudioProfilesCallbacks;
    private RemoteCallbackList<IBluetoothQualityReportReadyCallback>
    private RemoteCallbackList<IBluetoothQualityReportReadyCallback>
            mBluetoothQualityReportReadyCallbacks;
            mBluetoothQualityReportReadyCallbacks;
    private Set<BluetoothDevice> mDevicesPendingAudioProfileChanges = new HashSet<>();
    // Map<groupId, PendingAudioProfilePreferenceRequest>
    private final Map<Integer, PendingAudioProfilePreferenceRequest>
            mCsipGroupsPendingAudioProfileChanges = new HashMap<>();
    //Only BluetoothManagerService should be registered
    //Only BluetoothManagerService should be registered
    private RemoteCallbackList<IBluetoothCallback> mCallbacks;
    private RemoteCallbackList<IBluetoothCallback> mCallbacks;
    private int mCurrentRequestId;
    private int mCurrentRequestId;
@@ -408,6 +411,7 @@ public class AdapterService extends Service {
    private static final int MESSAGE_PROFILE_SERVICE_STATE_CHANGED = 1;
    private static final int MESSAGE_PROFILE_SERVICE_STATE_CHANGED = 1;
    private static final int MESSAGE_PROFILE_SERVICE_REGISTERED = 2;
    private static final int MESSAGE_PROFILE_SERVICE_REGISTERED = 2;
    private static final int MESSAGE_PROFILE_SERVICE_UNREGISTERED = 3;
    private static final int MESSAGE_PROFILE_SERVICE_UNREGISTERED = 3;
    private static final int MESSAGE_PREFERRED_AUDIO_PROFILES_AUDIO_FRAMEWORK_TIMEOUT = 4;


    class AdapterServiceHandler extends Handler {
    class AdapterServiceHandler extends Handler {
        @Override
        @Override
@@ -427,6 +431,21 @@ public class AdapterService extends Service {
                    verboseLog("handleMessage() - MESSAGE_PROFILE_SERVICE_UNREGISTERED");
                    verboseLog("handleMessage() - MESSAGE_PROFILE_SERVICE_UNREGISTERED");
                    unregisterProfileService((ProfileService) msg.obj);
                    unregisterProfileService((ProfileService) msg.obj);
                    break;
                    break;
                case MESSAGE_PREFERRED_AUDIO_PROFILES_AUDIO_FRAMEWORK_TIMEOUT:
                    errorLog("handleMessage() - "
                            + "MESSAGE_PREFERRED_PROFILE_CHANGE_AUDIO_FRAMEWORK_TIMEOUT");
                    int groupId = (int) msg.obj;

                    synchronized (mCsipGroupsPendingAudioProfileChanges) {
                        removeFromPendingAudioProfileChanges(groupId);
                        PendingAudioProfilePreferenceRequest request =
                                mCsipGroupsPendingAudioProfileChanges.remove(groupId);
                        Log.e(TAG, "Preferred audio profiles change audio framework timeout for "
                                + "device " + request.mDeviceRequested);
                        sendPreferredAudioProfilesCallbackToApps(request.mDeviceRequested,
                                request.mRequestedPreferences, BluetoothStatusCodes.ERROR_TIMEOUT);
                    }
                    break;
            }
            }
        }
        }


@@ -503,6 +522,34 @@ public class AdapterService extends Service {


    private final AdapterServiceHandler mHandler = new AdapterServiceHandler();
    private final AdapterServiceHandler mHandler = new AdapterServiceHandler();


    /**
     * Stores information about requests made to the audio framework arising from calls to
     * {@link BluetoothAdapter#setPreferredAudioProfiles(BluetoothDevice, Bundle)}.
     */
    private static class PendingAudioProfilePreferenceRequest {
        // The newly requested preferences
        final Bundle mRequestedPreferences;
        // Reference counter for how many calls are pending completion in the audio framework
        int mRemainingRequestsToAudioFramework;
        // The device with which the request was made. Used for sending the callback.
        final BluetoothDevice mDeviceRequested;

        /**
         * Constructs an entity to store information about pending preferred audio profile changes.
         *
         * @param preferences newly requested preferences
         * @param numRequestsToAudioFramework how many active device changed requests are sent to
         *                                    the audio framework
         * @param device the device with which the request was made
         */
        PendingAudioProfilePreferenceRequest(Bundle preferences,
                int numRequestsToAudioFramework, BluetoothDevice device) {
            mRequestedPreferences = preferences;
            mRemainingRequestsToAudioFramework = numRequestsToAudioFramework;
            mDeviceRequested = device;
        }
    }

    @Override
    @Override
    @RequiresPermission(
    @RequiresPermission(
            allOf = {
            allOf = {
@@ -4868,33 +4915,164 @@ public class AdapterService extends Service {
            Log.e(TAG, "setPreferredAudioProfiles: Not a dual mode audio device");
            Log.e(TAG, "setPreferredAudioProfiles: Not a dual mode audio device");
            return BluetoothStatusCodes.ERROR_NOT_DUAL_MODE_AUDIO_DEVICE;
            return BluetoothStatusCodes.ERROR_NOT_DUAL_MODE_AUDIO_DEVICE;
        }
        }
        // Gets the lead device in the CSIP group to set the preference
        // Checks if the device is part of an LE Audio group
        BluetoothDevice groupLead = mLeAudioService.getLeadDevice(device);
        int groupId = mLeAudioService.getGroupId(device);
        if (groupLead == null) {
        List<BluetoothDevice> groupDevices = mLeAudioService.getGroupDevices(groupId);
        if (groupDevices.isEmpty()) {
            return BluetoothStatusCodes.ERROR_DEVICE_NOT_BONDED;
            return BluetoothStatusCodes.ERROR_DEVICE_NOT_BONDED;
        }
        }


        synchronized (mDevicesPendingAudioProfileChanges) {
            if (mDevicesPendingAudioProfileChanges.contains(groupLead)) {
                return BluetoothStatusCodes.ERROR_ANOTHER_ACTIVE_REQUEST;
            }

        // Copies relevant keys & values from modeToProfile bundle
        // Copies relevant keys & values from modeToProfile bundle
        Bundle strippedPreferences = new Bundle();
        Bundle strippedPreferences = new Bundle();
        if (modeToProfileBundle.containsKey(BluetoothAdapter.AUDIO_MODE_OUTPUT_ONLY)
        if (modeToProfileBundle.containsKey(BluetoothAdapter.AUDIO_MODE_OUTPUT_ONLY)
                    && isOutputOnlyAudioSupported(mLeAudioService.getGroupDevices(device))) {
                && isOutputOnlyAudioSupported(groupDevices)) {
                strippedPreferences.putInt(BluetoothAdapter.AUDIO_MODE_OUTPUT_ONLY,
            int outputOnlyProfile = modeToProfileBundle.getInt(
                        modeToProfileBundle.getInt(BluetoothAdapter.AUDIO_MODE_OUTPUT_ONLY));
                    BluetoothAdapter.AUDIO_MODE_OUTPUT_ONLY);
            if (outputOnlyProfile != BluetoothProfile.A2DP
                    && outputOnlyProfile != BluetoothProfile.LE_AUDIO) {
                throw new IllegalArgumentException("AUDIO_MODE_OUTPUT_ONLY has invalid value: "
                        + outputOnlyProfile);
            }
            strippedPreferences.putInt(BluetoothAdapter.AUDIO_MODE_OUTPUT_ONLY, outputOnlyProfile);
        }
        }
        if (modeToProfileBundle.containsKey(BluetoothAdapter.AUDIO_MODE_DUPLEX)
        if (modeToProfileBundle.containsKey(BluetoothAdapter.AUDIO_MODE_DUPLEX)
                    && isDuplexAudioSupported(mLeAudioService.getGroupDevices(device))) {
                && isDuplexAudioSupported(groupDevices)) {
                strippedPreferences.putInt(BluetoothAdapter.AUDIO_MODE_DUPLEX,
            int duplexProfile = modeToProfileBundle.getInt(BluetoothAdapter.AUDIO_MODE_DUPLEX);
                        modeToProfileBundle.getInt(BluetoothAdapter.AUDIO_MODE_DUPLEX));
            if (duplexProfile != BluetoothProfile.HEADSET
                    && duplexProfile != BluetoothProfile.LE_AUDIO) {
                throw new IllegalArgumentException("AUDIO_MODE_DUPLEX has invalid value: "
                        + duplexProfile);
            }
            strippedPreferences.putInt(BluetoothAdapter.AUDIO_MODE_DUPLEX, duplexProfile);
        }

        synchronized (mCsipGroupsPendingAudioProfileChanges) {
            if (mCsipGroupsPendingAudioProfileChanges.containsKey(groupId)) {
                return BluetoothStatusCodes.ERROR_ANOTHER_ACTIVE_REQUEST;
            }
            }


            mDevicesPendingAudioProfileChanges.add(groupLead);
            Bundle previousPreferences = getPreferredAudioProfiles(device);
            return mDatabaseManager.setPreferredAudioProfiles(groupLead,

            int dbResult = mDatabaseManager.setPreferredAudioProfiles(groupDevices,
                    strippedPreferences);
                    strippedPreferences);
            if (dbResult != BluetoothStatusCodes.SUCCESS) {
                return dbResult;
            }

            /* Populates the HashMap to hold requests on the groupId. We will update
            numRequestsToAudioFramework after we make requests to the audio framework */
            PendingAudioProfilePreferenceRequest holdRequest =
                    new PendingAudioProfilePreferenceRequest(strippedPreferences, 0, device);
            mCsipGroupsPendingAudioProfileChanges.put(groupId, holdRequest);

            // Notifies audio framework via the handler thread to avoid this blocking calls
            mHandler.post(() -> sendPreferredAudioProfileChangeToAudioFramework(
                    device, strippedPreferences, previousPreferences));
            return BluetoothStatusCodes.SUCCESS;
        }
    }

    /**
     * Sends the updated preferred audio profiles to the audio framework.
     *
     * @param device is the device with updated audio preferences
     * @param strippedPreferences is a {@link Bundle} containing the preferences
     */
    private void sendPreferredAudioProfileChangeToAudioFramework(BluetoothDevice device,
            Bundle strippedPreferences, Bundle previousPreferences) {
        int newOutput = strippedPreferences.getInt(BluetoothAdapter.AUDIO_MODE_OUTPUT_ONLY);
        int newDuplex = strippedPreferences.getInt(BluetoothAdapter.AUDIO_MODE_DUPLEX);
        int previousOutput = previousPreferences.getInt(BluetoothAdapter.AUDIO_MODE_OUTPUT_ONLY);
        int previousDuplex = previousPreferences.getInt(BluetoothAdapter.AUDIO_MODE_DUPLEX);

        Log.i(TAG, "sendPreferredAudioProfileChangeToAudioFramework: changing output from "
                + BluetoothProfile.getProfileName(previousOutput) + " to "
                + BluetoothProfile.getProfileName(newOutput) + " and duplex from "
                + BluetoothProfile.getProfileName(previousDuplex) + " to "
                + BluetoothProfile.getProfileName(newDuplex));

        // If no change from existing preferences, do not inform audio framework
        if (previousOutput == newOutput && previousDuplex == newDuplex) {
            Log.i(TAG, "No change to preferred audio profiles, no requests to Audio FW");
            sendPreferredAudioProfilesCallbackToApps(device, strippedPreferences,
                    BluetoothStatusCodes.SUCCESS);
            return;
        }

        int numRequestsToAudioFw = 0;

        // Checks if the device is part of an LE Audio group
        int groupId = mLeAudioService.getGroupId(device);
        List<BluetoothDevice> groupDevices = mLeAudioService.getGroupDevices(groupId);
        if (groupDevices.isEmpty()) {
            Log.i(TAG, "sendPreferredAudioProfileChangeToAudioFramework: Empty LEA group for "
                    + "device - " + device);
            sendPreferredAudioProfilesCallbackToApps(device, strippedPreferences,
                    BluetoothStatusCodes.ERROR_DEVICE_NOT_BONDED);
            return;
        }

        synchronized (mCsipGroupsPendingAudioProfileChanges) {

            if (previousOutput != newOutput) {
                if (newOutput == BluetoothProfile.A2DP && mA2dpService.getActiveDevice() != null
                        && groupDevices.contains(mA2dpService.getActiveDevice())) {
                    Log.i(TAG, "Sent change for AUDIO_MODE_OUTPUT_ONLY to A2DP to Audio FW");
                    numRequestsToAudioFw +=
                            mA2dpService.sendPreferredAudioProfileChangeToAudioFramework();
                } else if (newOutput == BluetoothProfile.LE_AUDIO
                        && mLeAudioService.getActiveGroupId() == groupId) {
                    Log.i(TAG, "Sent change for AUDIO_MODE_OUTPUT_ONLY to LE_AUDIO to Audio FW");
                    numRequestsToAudioFw +=
                            mLeAudioService.sendPreferredAudioProfileChangeToAudioFramework();
                }
            }

            if (previousDuplex != newDuplex) {
                if (newDuplex == BluetoothProfile.HEADSET
                        && mHeadsetService.getActiveDevice() != null
                        && groupDevices.contains(mHeadsetService.getActiveDevice())) {
                    Log.i(TAG, "Sent change for AUDIO_MODE_DUPLEX to HFP to Audio FW");
                    // TODO(b/275426145): Add similar HFP method in BluetoothProfileConnectionInfo
                    numRequestsToAudioFw +=
                            mA2dpService.sendPreferredAudioProfileChangeToAudioFramework();
                } else if (newDuplex == BluetoothProfile.LE_AUDIO
                        && mLeAudioService.getActiveGroupId() == groupId) {
                    Log.i(TAG, "Sent change for AUDIO_MODE_DUPLEX to LE_AUDIO to Audio FW");
                    numRequestsToAudioFw +=
                            mLeAudioService.sendPreferredAudioProfileChangeToAudioFramework();
                }
            }

            Log.i(TAG,
                    "sendPreferredAudioProfileChangeToAudioFramework: sent " + numRequestsToAudioFw
                            + " request(s) to the Audio Framework for device: " + device);

            if (numRequestsToAudioFw > 0) {
                mCsipGroupsPendingAudioProfileChanges.put(groupId,
                        new PendingAudioProfilePreferenceRequest(strippedPreferences,
                                numRequestsToAudioFw, device));

                Message m = mHandler.obtainMessage(
                        MESSAGE_PREFERRED_AUDIO_PROFILES_AUDIO_FRAMEWORK_TIMEOUT);
                m.obj = groupId;
                mHandler.sendMessageDelayed(m, PREFERRED_AUDIO_PROFILE_CHANGE_TIMEOUT.toMillis());
                return;
            }
        }
        sendPreferredAudioProfilesCallbackToApps(device, strippedPreferences,
                BluetoothStatusCodes.SUCCESS);
    }

    private void removeFromPendingAudioProfileChanges(int groupId) {
        synchronized (mCsipGroupsPendingAudioProfileChanges) {
            Log.i(TAG, "removeFromPendingAudioProfileChanges: Timeout on change for groupId="
                    + groupId);
            if (!mCsipGroupsPendingAudioProfileChanges.containsKey(groupId)) {
                Log.e(TAG, "removeFromPendingAudioProfileChanges( " + groupId + ", " + groupId
                        + ") is not pending");
                return;
            }
        }
        }
    }
    }


@@ -4906,42 +5084,81 @@ public class AdapterService extends Service {
     * @param device the remote device whose preferred audio profiles have been changed
     * @param device the remote device whose preferred audio profiles have been changed
     * @return whether the Bluetooth stack acknowledged the change successfully
     * @return whether the Bluetooth stack acknowledged the change successfully
     */
     */

    private int notifyActiveDeviceChangeApplied(BluetoothDevice device) {
    private int notifyActiveDeviceChangeApplied(BluetoothDevice device) {
        // Gets the lead device in the CSIP group to set the preference
        if (mLeAudioService == null) {
        BluetoothDevice groupLead = mLeAudioService.getLeadDevice(device);
            Log.e(TAG, "LE Audio profile not enabled");
        if (groupLead == null) {
            return BluetoothStatusCodes.ERROR_PROFILE_NOT_CONNECTED;
        }

        int groupId = mLeAudioService.getGroupId(device);
        if (groupId == LE_AUDIO_GROUP_ID_INVALID) {
            return BluetoothStatusCodes.ERROR_DEVICE_NOT_BONDED;
            return BluetoothStatusCodes.ERROR_DEVICE_NOT_BONDED;
        }
        }


        synchronized (mDevicesPendingAudioProfileChanges) {
        synchronized (mCsipGroupsPendingAudioProfileChanges) {
            if (!mDevicesPendingAudioProfileChanges.contains(groupLead)) {
            if (!mCsipGroupsPendingAudioProfileChanges.containsKey(groupId)) {
                Log.e(TAG, "notifyActiveDeviceChangeApplied, but no pending request for "
                Log.e(TAG, "notifyActiveDeviceChangeApplied, but no pending request for "
                        + "device: " + groupLead);
                        + "groupId: " + groupId);
                return BluetoothStatusCodes.ERROR_UNKNOWN;
                return BluetoothStatusCodes.ERROR_UNKNOWN;
            }
            }


            if (mPreferredAudioProfilesCallbacks != null) {
            PendingAudioProfilePreferenceRequest pendingRequest =
                    mCsipGroupsPendingAudioProfileChanges.get(groupId);

            // If this is the final audio framework request, send callback to apps
            if (pendingRequest.mRemainingRequestsToAudioFramework == 1) {
                Log.i(TAG, "notifyActiveDeviceChangeApplied: Complete for device "
                        + pendingRequest.mDeviceRequested);
                sendPreferredAudioProfilesCallbackToApps(pendingRequest.mDeviceRequested,
                        pendingRequest.mRequestedPreferences, BluetoothStatusCodes.SUCCESS);
                // Removes the timeout from the handler
                mHandler.removeMessages(
                        MESSAGE_PREFERRED_AUDIO_PROFILES_AUDIO_FRAMEWORK_TIMEOUT, groupId);
            } else if (pendingRequest.mRemainingRequestsToAudioFramework > 1) {
                PendingAudioProfilePreferenceRequest updatedPendingRequest =
                        new PendingAudioProfilePreferenceRequest(
                                pendingRequest.mRequestedPreferences,
                                pendingRequest.mRemainingRequestsToAudioFramework - 1,
                                pendingRequest.mDeviceRequested);
                Log.i(TAG, "notifyActiveDeviceChangeApplied: Updating device "
                        + updatedPendingRequest.mDeviceRequested
                        + " with new remaining requests count="
                        + updatedPendingRequest.mRemainingRequestsToAudioFramework);
                mCsipGroupsPendingAudioProfileChanges.put(groupId, updatedPendingRequest);
            } else {
                Log.i(TAG, "notifyActiveDeviceChangeApplied: " + pendingRequest.mDeviceRequested
                        + " has no remaining requests to audio framework, but is still present in"
                        + " mCsipGroupsPendingAudioProfileChanges");
            }
        }

        return BluetoothStatusCodes.SUCCESS;
    }

    private void sendPreferredAudioProfilesCallbackToApps(BluetoothDevice device,
            Bundle preferredAudioProfiles, int status) {
        if (mPreferredAudioProfilesCallbacks == null) {
            return;
        }

        int n = mPreferredAudioProfilesCallbacks.beginBroadcast();
        int n = mPreferredAudioProfilesCallbacks.beginBroadcast();
                debugLog("notifyActiveDeviceChangeApplied() - Broadcasting audio profile "
        debugLog("sendPreferredAudioProfilesCallbackToApps() - Broadcasting audio profile "
                        + "change applied to device: " + groupLead + " to " + n + " receivers.");
                + "change callback to device: " + device + " and status=" + status + " to " + n
                + " receivers.");
        for (int i = 0; i < n; i++) {
        for (int i = 0; i < n; i++) {
            try {
            try {
                mPreferredAudioProfilesCallbacks.getBroadcastItem(i)
                mPreferredAudioProfilesCallbacks.getBroadcastItem(i)
                        .onPreferredAudioProfilesChanged(device,
                        .onPreferredAudioProfilesChanged(device,
                                        getPreferredAudioProfiles(device),
                                preferredAudioProfiles,
                                        BluetoothStatusCodes.SUCCESS);
                                status);
            } catch (RemoteException e) {
            } catch (RemoteException e) {
                        debugLog("notifyActiveDeviceChangeApplied() - Callback #" + i
                debugLog("sendPreferredAudioProfilesCallbackToApps() - Callback #" + i
                        + " failed (" + e + ")");
                        + " failed (" + e + ")");
            }
            }
        }
        }
        mPreferredAudioProfilesCallbacks.finishBroadcast();
        mPreferredAudioProfilesCallbacks.finishBroadcast();
    }
    }
            mDevicesPendingAudioProfileChanges.remove(groupLead);
        }

        return BluetoothStatusCodes.SUCCESS;
    }


    // ----API Methods--------
    // ----API Methods--------


+71 −26
Original line number Original line Diff line number Diff line
@@ -778,41 +778,86 @@ public class DatabaseManager {
     * Sets the preferred profile for the supplied audio modes. See
     * Sets the preferred profile for the supplied audio modes. See
     * {@link BluetoothAdapter#setPreferredAudioProfiles(BluetoothDevice, Bundle)} for more details.
     * {@link BluetoothAdapter#setPreferredAudioProfiles(BluetoothDevice, Bundle)} for more details.
     *
     *
     * @param device is the remote device for which we are setting the preferred audio profiles
     * If a device in the group has been designated to store the preference for the group, this will
     * update its database preferences. If there is not one designated, the first device from the
     * group list will be chosen for this purpose. From then on, any preferred audio profile changes
     * for this group will be stored on that device.
     *
     * @param groupDevices is the CSIP group for which we are setting the preferred audio profiles
     * @param modeToProfileBundle contains the preferred profile
     * @param modeToProfileBundle contains the preferred profile
     * @return
     * @return whether the new preferences were saved in the database
     */
     */
    public int setPreferredAudioProfiles(BluetoothDevice device, Bundle modeToProfileBundle) {
    public int setPreferredAudioProfiles(List<BluetoothDevice> groupDevices,
            Bundle modeToProfileBundle) {
        Objects.requireNonNull(groupDevices, "groupDevices must not be null");
        Objects.requireNonNull(modeToProfileBundle, "modeToProfileBundle must not be null");
        if (groupDevices.isEmpty()) {
            throw new IllegalArgumentException("groupDevices cannot be empty");
        }
        int outputProfile = modeToProfileBundle.getInt(
                BluetoothAdapter.AUDIO_MODE_OUTPUT_ONLY);
        int duplexProfile = modeToProfileBundle.getInt(BluetoothAdapter.AUDIO_MODE_DUPLEX);
        boolean isPreferenceSet = false;

        synchronized (mMetadataCache) {
        synchronized (mMetadataCache) {
            for (BluetoothDevice device: groupDevices) {
                if (device == null) {
                if (device == null) {
                    Log.e(TAG, "setPreferredAudioProfiles: device is null");
                    Log.e(TAG, "setPreferredAudioProfiles: device is null");
                    throw new IllegalArgumentException("setPreferredAudioProfiles: device is null");
                    throw new IllegalArgumentException("setPreferredAudioProfiles: device is null");
                }
                }


                String address = device.getAddress();
                String address = device.getAddress();

                if (!mMetadataCache.containsKey(address)) {
                if (!mMetadataCache.containsKey(address)) {
                    Log.e(TAG, "setPreferredAudioProfiles: Device not found in the database");
                    return BluetoothStatusCodes.ERROR_DEVICE_NOT_BONDED;
                    return BluetoothStatusCodes.ERROR_DEVICE_NOT_BONDED;
                }
                }


            // Updates preferred audio profiles for the device
                // Finds the device in the group which stores the group's preferences
                Metadata metadata = mMetadataCache.get(address);
                Metadata metadata = mMetadataCache.get(address);
            int outputProfile = modeToProfileBundle.getInt(BluetoothAdapter.AUDIO_MODE_OUTPUT_ONLY);
                if (outputProfile != 0 && (metadata.preferred_output_only_profile != 0
            int duplexProfile = modeToProfileBundle.getInt(BluetoothAdapter.AUDIO_MODE_DUPLEX);
                        || metadata.preferred_duplex_profile != 0)) {
                    Log.i(TAG, "setPreferredAudioProfiles: Updating OUTPUT_ONLY audio profile for "
                            + "device: " + device + " to "
                            + BluetoothProfile.getProfileName(outputProfile));
                    metadata.preferred_output_only_profile = outputProfile;
                    isPreferenceSet = true;
                }
                if (duplexProfile != 0 && (metadata.preferred_output_only_profile != 0
                        || metadata.preferred_duplex_profile != 0)) {
                    Log.i(TAG,
                            "setPreferredAudioProfiles: Updating DUPLEX audio profile for device: "
                                    + device + " to " + BluetoothProfile.getProfileName(
                                    duplexProfile));
                    metadata.preferred_duplex_profile = duplexProfile;
                    isPreferenceSet = true;
                }

                updateDatabase(metadata);
            }

            // If no device in the group has a preference set, choose the first device in the list
            if (!isPreferenceSet) {
                Log.i(TAG, "No device in the group has preferred audio profiles set");
                BluetoothDevice firstGroupDevice = groupDevices.get(0);
                // Updates preferred audio profiles for the device
                Metadata metadata = mMetadataCache.get(firstGroupDevice.getAddress());
                if (outputProfile != 0) {
                if (outputProfile != 0) {
                    Log.i(TAG, "setPreferredAudioProfiles: Updating output only audio profile for "
                    Log.i(TAG, "setPreferredAudioProfiles: Updating output only audio profile for "
                        + "device: " + device + " to "
                            + "device: " + firstGroupDevice + " to "
                            + BluetoothProfile.getProfileName(outputProfile));
                            + BluetoothProfile.getProfileName(outputProfile));
                    metadata.preferred_output_only_profile = outputProfile;
                    metadata.preferred_output_only_profile = outputProfile;
                }
                }
                if (duplexProfile != 0) {
                if (duplexProfile != 0) {
                Log.i(TAG, "setPreferredAudioProfiles: Updating duplex audio profile for device: "
                    Log.i(TAG,
                        + device + " to " + BluetoothProfile.getProfileName(duplexProfile));
                            "setPreferredAudioProfiles: Updating duplex audio profile for device: "
                                    + firstGroupDevice + " to " + BluetoothProfile.getProfileName(
                                    duplexProfile));
                    metadata.preferred_duplex_profile = duplexProfile;
                    metadata.preferred_duplex_profile = duplexProfile;
                }
                }


                updateDatabase(metadata);
                updateDatabase(metadata);
            }
            }
        }
        return BluetoothStatusCodes.SUCCESS;
        return BluetoothStatusCodes.SUCCESS;
    }
    }


+90 −0

File changed.

Preview size limit exceeded, changes collapsed.