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

Commit a76c284a authored by Łukasz Rymanowski's avatar Łukasz Rymanowski Committed by Automerger Merge Worker
Browse files

LeAudioService: Set inband ringtone flag only for active devices am: 3ee3167b

parents 2699f32d 3ee3167b
Loading
Loading
Loading
Loading
+5 −0
Original line number Diff line number Diff line
@@ -29,6 +29,7 @@ import com.android.bluetooth.hid.HidHostService;
import com.android.bluetooth.le_audio.LeAudioService;
import com.android.bluetooth.mcp.McpService;
import com.android.bluetooth.pan.PanService;
import com.android.bluetooth.tbs.TbsService;
import com.android.bluetooth.vc.VolumeControlService;

// Factory class to create instances of static services. Useful in mocking the service objects.
@@ -73,6 +74,10 @@ public class ServiceFactory {
        return McpService.getMcpService();
    }

    public TbsService getTbsService() {
        return TbsService.getTbsService();
    }

    public VolumeControlService getVolumeControlService() {
        return VolumeControlService.getVolumeControlService();
    }
+168 −33
Original line number Diff line number Diff line
@@ -67,6 +67,7 @@ import com.android.bluetooth.btservice.storage.DatabaseManager;
import com.android.bluetooth.hfp.HeadsetService;
import com.android.bluetooth.mcp.McpService;
import com.android.bluetooth.tbs.TbsGatt;
import com.android.bluetooth.tbs.TbsService;
import com.android.bluetooth.vc.VolumeControlService;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
@@ -129,6 +130,9 @@ public class LeAudioService extends ProfileService {
    AudioManager mAudioManager;
    LeAudioTmapGattServer mTmapGattServer;

    @VisibleForTesting
    TbsService mTbsService;

    @VisibleForTesting
    McpService mMcpService;

@@ -142,12 +146,13 @@ public class LeAudioService extends ProfileService {
    RemoteCallbackList<IBluetoothLeAudioCallback> mLeAudioCallbacks;

    private class LeAudioGroupDescriptor {
        LeAudioGroupDescriptor() {
        LeAudioGroupDescriptor(boolean isInbandRingtonEnabled) {
            mIsConnected = false;
            mIsActive = false;
            mDirection = AUDIO_DIRECTION_NONE;
            mCodecStatus = null;
            mLostLeadDeviceWhileStreaming = null;
            mInbandRingtoneEnabled = isInbandRingtonEnabled;
        }

        public Boolean mIsConnected;
@@ -156,20 +161,23 @@ public class LeAudioService extends ProfileService {
        public BluetoothLeAudioCodecStatus mCodecStatus;
        /* This can be non empty only for the streaming time */
        BluetoothDevice mLostLeadDeviceWhileStreaming;
        Boolean mInbandRingtoneEnabled;
    }

    private static class LeAudioDeviceDescriptor {
        LeAudioDeviceDescriptor() {
        LeAudioDeviceDescriptor(boolean isInbandRingtonEnabled) {
            mStateMachine = null;
            mGroupId = LE_AUDIO_GROUP_ID_INVALID;
            mSinkAudioLocation = BluetoothLeAudio.AUDIO_LOCATION_INVALID;
            mDirection = AUDIO_DIRECTION_NONE;
            mDevInbandRingtoneEnabled = isInbandRingtonEnabled;
        }

        public LeAudioStateMachine mStateMachine;
        public Integer mGroupId;
        public Integer mSinkAudioLocation;
        public Integer mDirection;
        Boolean mDevInbandRingtoneEnabled;
    }

    List<BluetoothLeAudioCodecConfig> mInputLocalCodecCapabilities = new ArrayList<>();
@@ -411,6 +419,7 @@ public class LeAudioService extends ProfileService {
        mAdapterService = null;
        mAudioManager = null;
        mMcpService = null;
        mTbsService = null;
        mVolumeControlService = null;

        return true;
@@ -454,7 +463,8 @@ public class LeAudioService extends ProfileService {
        return mVolumeControlService.getAudioDeviceGroupVolume(groupId);
    }

    LeAudioDeviceDescriptor createDeviceDescriptor(BluetoothDevice device) {
    LeAudioDeviceDescriptor createDeviceDescriptor(BluetoothDevice device,
            boolean isInbandRingtoneEnabled) {
        LeAudioDeviceDescriptor descriptor = mDeviceDescriptors.get(device);
        if (descriptor == null) {

@@ -465,7 +475,7 @@ public class LeAudioService extends ProfileService {
                return null;
            }

            mDeviceDescriptors.put(device, new LeAudioDeviceDescriptor());
            mDeviceDescriptors.put(device, new LeAudioDeviceDescriptor(isInbandRingtoneEnabled));
            descriptor = mDeviceDescriptors.get(device);
            Log.d(TAG, "Created descriptor for device: " + device);
        } else {
@@ -491,7 +501,13 @@ public class LeAudioService extends ProfileService {
        }

        synchronized (mGroupLock) {
            if (createDeviceDescriptor(device) == null) {
            boolean isInbandRingtoneEnabled = false;
            int groupId = getGroupId(device);
            if (groupId != LE_AUDIO_GROUP_ID_INVALID) {
                isInbandRingtoneEnabled = getGroupDescriptor(groupId).mInbandRingtoneEnabled;
            }

            if (createDeviceDescriptor(device, isInbandRingtoneEnabled) == null) {
                return false;
            }

@@ -1420,6 +1436,7 @@ public class LeAudioService extends ProfileService {

            if (descriptor.mIsActive) {
                notifyGroupStatusChanged(groupId, LeAudioStackEvent.GROUP_STATUS_ACTIVE);
                updateInbandRingtoneForTheGroup(groupId);
            }
        }
    }
@@ -1439,6 +1456,7 @@ public class LeAudioService extends ProfileService {
            if (DBG) Log.d(TAG, "Clear for group: " + groupId);
            clearLostDevicesWhileStreaming(descriptor);
            notifyGroupStatusChanged(groupId, LeAudioStackEvent.GROUP_STATUS_INACTIVE);
            updateInbandRingtoneForTheGroup(groupId);
        }
    }

@@ -1473,6 +1491,67 @@ public class LeAudioService extends ProfileService {
        mHfpHandoverDevice = null;
    }

    void updateInbandRingtoneForTheGroup(int groupId) {
        if (!mLeAudioInbandRingtoneSupportedByPlatform) {
            if (DBG) {
                Log.d(TAG, "Platform does not support inband ringtone");
            }
            return;
        }

        synchronized (mGroupLock) {
            LeAudioGroupDescriptor groupDescriptor = getGroupDescriptor(groupId);
            if (groupDescriptor == null) {
                Log.e(TAG, "group descriptor for " + groupId + " does not exist");
                return;
            }

            boolean isRingtoneEnabled = groupDescriptor.mIsActive;

            if (DBG) {
                Log.d(TAG, "updateInbandRingtoneForTheGroup old: "
                        + groupDescriptor.mInbandRingtoneEnabled + " new: " + isRingtoneEnabled);
            }

            /* If at least one device from the group removes the Ringtone from available
            * context types, the inband ringtone will be removed
            */
            groupDescriptor.mInbandRingtoneEnabled = isRingtoneEnabled;
            TbsService tbsService = getTbsService();
            if (tbsService == null) {
                Log.w(TAG, "updateInbandRingtoneForTheGroup, tbsService not available");
                return;
            }

            for (Map.Entry<BluetoothDevice, LeAudioDeviceDescriptor> entry :
                                                    mDeviceDescriptors.entrySet()) {
                if (entry.getValue().mGroupId == groupId) {
                    BluetoothDevice device = entry.getKey();
                    LeAudioDeviceDescriptor deviceDescriptor = entry.getValue();
                    Log.i(TAG, "updateInbandRingtoneForTheGroup, setting inband ringtone to: "
                                + groupDescriptor.mInbandRingtoneEnabled + " for " + device
                                + " " + deviceDescriptor.mDevInbandRingtoneEnabled);
                    if (groupDescriptor.mInbandRingtoneEnabled
                                    == deviceDescriptor.mDevInbandRingtoneEnabled) {
                        if (DBG) {
                            Log.d(TAG, "Device " + device + " has already set inband ringtone to "
                                            + groupDescriptor.mInbandRingtoneEnabled);
                        }
                        continue;
                    }

                    deviceDescriptor.mDevInbandRingtoneEnabled =
                            groupDescriptor.mInbandRingtoneEnabled;
                    if (deviceDescriptor.mDevInbandRingtoneEnabled) {
                        tbsService.setInbandRingtoneSupport(device);
                    } else {
                        tbsService.clearInbandRingtoneSupport(device);
                    }
                }
            }
        }
    }

    // Suppressed since this is part of a local process
    @SuppressLint("AndroidFrameworkRequiresPermission")
    void messageFromNative(LeAudioStackEvent stackEvent) {
@@ -2077,10 +2156,18 @@ public class LeAudioService extends ProfileService {
     * @return true if inband ringtone is enabled, false otherwise
     */
    public boolean isInbandRingtoneEnabled(int groupId) {
        /* TODO Take into account device available context type */
        if (!mLeAudioInbandRingtoneSupportedByPlatform) {
            return mLeAudioInbandRingtoneSupportedByPlatform;
        }

        LeAudioGroupDescriptor descriptor = getGroupDescriptor(groupId);
        if (descriptor == null) {
            return false;
        }

        return descriptor.mInbandRingtoneEnabled;
    }

    /**
     * Set In Call state
     * @param inCall True if device in call (any state), false otherwise.
@@ -2223,6 +2310,15 @@ public class LeAudioService extends ProfileService {
        }
    }

    TbsService getTbsService() {
        if (mTbsService != null) {
            return mTbsService;
        }

        mTbsService = mServiceFactory.getTbsService();
        return mTbsService;
    }

    McpService getMcpService() {
        if (mMcpService != null) {
            return mMcpService;
@@ -2289,9 +2385,20 @@ public class LeAudioService extends ProfileService {
                Log.d(TAG, "Device " + device + " added to group " + groupId);
            }

            LeAudioGroupDescriptor groupDescriptor = getGroupDescriptor(groupId);
            if (groupDescriptor == null) {
                mGroupDescriptors.put(groupId,
                        new LeAudioGroupDescriptor(false));
            }
            groupDescriptor = getGroupDescriptor(groupId);
            if (groupDescriptor == null) {
                Log.e(TAG, "Could not create group description");
                return;
            }
            LeAudioDeviceDescriptor deviceDescriptor = getDeviceDescriptor(device);
            if (deviceDescriptor == null) {
                deviceDescriptor = createDeviceDescriptor(device);
                deviceDescriptor = createDeviceDescriptor(device,
                        groupDescriptor.mInbandRingtoneEnabled);
                if (deviceDescriptor == null) {
                    Log.e(TAG, "handleGroupNodeAdded: Can't create descriptor for added from"
                            + " storage device: " + device);
@@ -2306,10 +2413,6 @@ public class LeAudioService extends ProfileService {
            }
            deviceDescriptor.mGroupId = groupId;

            LeAudioGroupDescriptor descriptor = mGroupDescriptors.get(groupId);
            if (descriptor == null) {
                mGroupDescriptors.put(groupId, new LeAudioGroupDescriptor());
            }
            notifyGroupNodeAdded(device, groupId);
        }

@@ -3320,27 +3423,59 @@ public class LeAudioService extends ProfileService {
        ProfileService.println(sb, "  mLeAudioIsInbandRingtoneSupported:"
                                + mLeAudioInbandRingtoneSupportedByPlatform);

        for (Map.Entry<BluetoothDevice, LeAudioDeviceDescriptor> entry
                : mDeviceDescriptors.entrySet()) {
            LeAudioDeviceDescriptor descriptor = entry.getValue();

            descriptor.mStateMachine.dump(sb);
            ProfileService.println(sb, "    mGroupId: " + descriptor.mGroupId);
            ProfileService.println(sb, "    mSinkAudioLocation: " + descriptor.mSinkAudioLocation);
            ProfileService.println(sb, "    mDirection: " + descriptor.mDirection);
        }

        for (Map.Entry<Integer, LeAudioGroupDescriptor> entry : mGroupDescriptors.entrySet()) {
            LeAudioGroupDescriptor descriptor = entry.getValue();
            Integer groupId = entry.getKey();
        int numberOfUngroupedDevs = 0;
        synchronized (mGroupLock) {
            for (Map.Entry<Integer, LeAudioGroupDescriptor> groupEntry
                                                : mGroupDescriptors.entrySet()) {
                LeAudioGroupDescriptor groupDescriptor = groupEntry.getValue();
                Integer groupId = groupEntry.getKey();
                ProfileService.println(sb, "Group: " + groupId);
            ProfileService.println(sb, "    isActive: " + descriptor.mIsActive);
            ProfileService.println(sb, "    isConnected: " + descriptor.mIsConnected);
            ProfileService.println(sb, "    mDirection: " + descriptor.mDirection);
                ProfileService.println(sb, "  isActive: " + groupDescriptor.mIsActive);
                ProfileService.println(sb, "  isConnected: " + groupDescriptor.mIsConnected);
                ProfileService.println(sb, "  mDirection: " + groupDescriptor.mDirection);
                ProfileService.println(sb, "  group lead: " + getConnectedGroupLeadDevice(groupId));
                ProfileService.println(sb, "  first device: " + getFirstDeviceFromGroup(groupId));
                ProfileService.println(sb, "  lost lead device: "
                    + descriptor.mLostLeadDeviceWhileStreaming);
                        + groupDescriptor.mLostLeadDeviceWhileStreaming);
                ProfileService.println(sb, "  mInbandRingtoneEnabled: "
                        + groupDescriptor.mInbandRingtoneEnabled);

                for (Map.Entry<BluetoothDevice, LeAudioDeviceDescriptor> deviceEntry
                        : mDeviceDescriptors.entrySet()) {
                    LeAudioDeviceDescriptor deviceDescriptor = deviceEntry.getValue();
                    if (deviceDescriptor.mGroupId != groupId) {
                        if (deviceDescriptor.mGroupId == LE_AUDIO_GROUP_ID_INVALID) {
                            numberOfUngroupedDevs++;
                        }
                        continue;
                    }

                    deviceDescriptor.mStateMachine.dump(sb);
                    ProfileService.println(sb, "    mDevInbandRingtoneEnabled: "
                            + deviceDescriptor.mDevInbandRingtoneEnabled);
                    ProfileService.println(sb, "    mSinkAudioLocation: "
                            + deviceDescriptor.mSinkAudioLocation);
                    ProfileService.println(sb, "    mDirection: " + deviceDescriptor.mDirection);
                }
            }
        }

        if (numberOfUngroupedDevs > 0) {
            ProfileService.println(sb, "UnGroup devices:");
            for (Map.Entry<BluetoothDevice, LeAudioDeviceDescriptor> entry
                    : mDeviceDescriptors.entrySet()) {
                LeAudioDeviceDescriptor deviceDescriptor = entry.getValue();
                if (deviceDescriptor.mGroupId != LE_AUDIO_GROUP_ID_INVALID) {
                    continue;
                }

                deviceDescriptor.mStateMachine.dump(sb);
                ProfileService.println(sb, "    mDevInbandRingtoneEnabled: "
                        + deviceDescriptor.mDevInbandRingtoneEnabled);
                ProfileService.println(sb, "    mSinkAudioLocation: "
                        + deviceDescriptor.mSinkAudioLocation);
                ProfileService.println(sb, "    mDirection: " + deviceDescriptor.mDirection);
            }
        }
    }
}
+42 −0
Original line number Diff line number Diff line
@@ -61,6 +61,7 @@ import com.android.bluetooth.btservice.ServiceFactory;
import com.android.bluetooth.btservice.storage.DatabaseManager;
import com.android.bluetooth.hfp.HeadsetService;
import com.android.bluetooth.mcp.McpService;
import com.android.bluetooth.tbs.TbsService;
import com.android.bluetooth.vc.VolumeControlService;

import org.junit.After;
@@ -112,6 +113,7 @@ public class LeAudioServiceTest {
    @Mock private LeAudioNativeInterface mNativeInterface;
    @Mock private LeAudioTmapGattServer mTmapGattServer;
    @Mock private McpService mMcpService;
    @Mock private TbsService mTbsService;
    @Mock private VolumeControlService mVolumeControlService;
    @Spy private LeAudioObjectsFactory mObjectsFactory = LeAudioObjectsFactory.getInstance();
    @Spy private ServiceFactory mServiceFactory = new ServiceFactory();
@@ -179,6 +181,7 @@ public class LeAudioServiceTest {
        startService();
        mService.mAudioManager = mAudioManager;
        mService.mMcpService = mMcpService;
        mService.mTbsService = mTbsService;
        mService.mServiceFactory = mServiceFactory;
        when(mServiceFactory.getVolumeControlService()).thenReturn(mVolumeControlService);

@@ -1030,6 +1033,11 @@ public class LeAudioServiceTest {
    @Test
    public void testSetActiveDeviceGroup() {
        int groupId = 1;
        /* AUDIO_DIRECTION_OUTPUT_BIT = 0x01 */
        int direction = 1;
        int snkAudioLocation = 3;
        int srcAudioLocation = 4;
        int availableContexts = 5;

        // Not connected device
        assertThat(mService.setActiveDevice(mSingleDevice)).isFalse();
@@ -1037,10 +1045,39 @@ public class LeAudioServiceTest {
        // Connected device
        doReturn(true).when(mNativeInterface).connectLeAudio(any(BluetoothDevice.class));
        connectTestDevice(mSingleDevice, testGroupId);

             // Add location support
        LeAudioStackEvent audioConfChangedEvent =
             new LeAudioStackEvent(LeAudioStackEvent.EVENT_TYPE_AUDIO_CONF_CHANGED);
        audioConfChangedEvent.device = mSingleDevice;
        audioConfChangedEvent.valueInt1 = direction;
        audioConfChangedEvent.valueInt2 = groupId;
        audioConfChangedEvent.valueInt3 = snkAudioLocation;
        audioConfChangedEvent.valueInt4 = srcAudioLocation;
        audioConfChangedEvent.valueInt5 = availableContexts;
        mService.messageFromNative(audioConfChangedEvent);

        assertThat(mService.setActiveDevice(mSingleDevice)).isTrue();
        verify(mNativeInterface).groupSetActive(groupId);

        //Set group and device as active
        LeAudioStackEvent groupStatusChangedEvent =
                new LeAudioStackEvent(LeAudioStackEvent.EVENT_TYPE_GROUP_STATUS_CHANGED);
        groupStatusChangedEvent.valueInt1 = groupId;
        groupStatusChangedEvent.valueInt2 = LeAudioStackEvent.GROUP_STATUS_ACTIVE;
        mService.messageFromNative(groupStatusChangedEvent);

        verify(mTbsService).setInbandRingtoneSupport(mSingleDevice);

        // no active device
        assertThat(mService.setActiveDevice(null)).isTrue();
        verify(mNativeInterface).groupSetActive(BluetoothLeAudio.GROUP_ID_INVALID);

        //Set group and device as inactive active
        groupStatusChangedEvent.valueInt2 = LeAudioStackEvent.GROUP_STATUS_INACTIVE;
        mService.messageFromNative(groupStatusChangedEvent);

        verify(mTbsService).clearInbandRingtoneSupport(mSingleDevice);
    }

    /**
@@ -1378,6 +1415,8 @@ public class LeAudioServiceTest {
        verify(mAudioManager, times(1)).handleBluetoothActiveDeviceChanged(any(), eq(leadDevice),
                any(BluetoothProfileConnectionInfo.class));

        verify(mTbsService).setInbandRingtoneSupport(mLeftDevice);
        verify(mTbsService).setInbandRingtoneSupport(mRightDevice);
    }

    /**
@@ -1449,6 +1488,9 @@ public class LeAudioServiceTest {

        verify(mAudioManager, times(1)).handleBluetoothActiveDeviceChanged(eq(null), eq(leadDevice),
                any(BluetoothProfileConnectionInfo.class));

        verify(mTbsService).setInbandRingtoneSupport(mLeftDevice);
        verify(mTbsService).setInbandRingtoneSupport(mRightDevice);
    }

    /**