diff options
author | Android Build Coastguard Worker <android-build-coastguard-worker@google.com> | 2021-12-14 02:09:30 +0000 |
---|---|---|
committer | Android Build Coastguard Worker <android-build-coastguard-worker@google.com> | 2021-12-14 02:09:30 +0000 |
commit | 729a7a44a8acf58a7073d6520ece9e69df2fa6eb (patch) | |
tree | 8ed05777c92c99d1bdfcbeab1fb384368b292be0 | |
parent | f60b9a30eb1fec740269b20e3772a7bdad4011a0 (diff) | |
parent | bbc23f9c61c5be50e5b25b3d684bb3e6d9a26ec5 (diff) |
Snap for 7995208 from bbc23f9c61c5be50e5b25b3d684bb3e6d9a26ec5 to tm-release
Change-Id: I279d238c408ce2fed930df8a9fd59068c344bdb5
16 files changed, 222 insertions, 13 deletions
diff --git a/android/app/src/com/android/bluetooth/BluetoothObexTransport.java b/android/app/src/com/android/bluetooth/BluetoothObexTransport.java index b1b5709a76..9fb8253a91 100644 --- a/android/app/src/com/android/bluetooth/BluetoothObexTransport.java +++ b/android/app/src/com/android/bluetooth/BluetoothObexTransport.java @@ -40,6 +40,8 @@ public class BluetoothObexTransport implements ObexTransport { private int mMaxTransmitPacketSize = PACKET_SIZE_UNSPECIFIED; private int mMaxReceivePacketSize = PACKET_SIZE_UNSPECIFIED; + private boolean mIsCoverArt = false; + public BluetoothObexTransport(BluetoothSocket socket) { this.mSocket = socket; } @@ -97,7 +99,9 @@ public class BluetoothObexTransport implements ObexTransport { @Override public int getMaxTransmitPacketSize() { - if (mSocket.getConnectionType() != BluetoothSocket.TYPE_L2CAP) { + if (mSocket.getConnectionType() != BluetoothSocket.TYPE_L2CAP + || (mIsCoverArt + && mMaxTransmitPacketSize != PACKET_SIZE_UNSPECIFIED)) { return mMaxTransmitPacketSize; } return mSocket.getMaxTransmitPacketSize(); @@ -125,4 +129,8 @@ public class BluetoothObexTransport implements ObexTransport { } return false; } + + public void setConnectionForCoverArt(boolean isCoverArt) { + mIsCoverArt = isCoverArt; + } } diff --git a/android/app/src/com/android/bluetooth/audio_util/helpers/Image.java b/android/app/src/com/android/bluetooth/audio_util/helpers/Image.java index c0623c6f46..231df9e276 100644 --- a/android/app/src/com/android/bluetooth/audio_util/helpers/Image.java +++ b/android/app/src/com/android/bluetooth/audio_util/helpers/Image.java @@ -56,13 +56,19 @@ public class Image { public Image(Context context, MediaMetadata metadata) { mContext = context; - String uri_art = metadata.getString(MediaMetadata.METADATA_KEY_ART_URI); - String uri_album_art = metadata.getString(MediaMetadata.METADATA_KEY_ALBUM_ART_URI); - String uri_icon = metadata.getString(MediaMetadata.METADATA_KEY_DISPLAY_ICON_URI); + String uri_art = null; + String uri_album_art = null; + String uri_icon = null; Bitmap bmp_art = metadata.getBitmap(MediaMetadata.METADATA_KEY_ART); Bitmap bmp_album_art = metadata.getBitmap(MediaMetadata.METADATA_KEY_ALBUM_ART); Bitmap bmp_icon = metadata.getBitmap(MediaMetadata.METADATA_KEY_DISPLAY_ICON); + if (mContext != null && Util.areUriImagesSupported(mContext)) { + uri_art = metadata.getString(MediaMetadata.METADATA_KEY_ART_URI); + uri_album_art = metadata.getString(MediaMetadata.METADATA_KEY_ALBUM_ART_URI); + uri_icon = metadata.getString(MediaMetadata.METADATA_KEY_DISPLAY_ICON_URI); + } + if (bmp_art != null) { setImage(bmp_art); } else if (bmp_album_art != null) { @@ -84,13 +90,19 @@ public class Image { public Image(Context context, Bundle bundle) { mContext = context; - String uri_art = bundle.getString(MediaMetadata.METADATA_KEY_ART_URI); - String uri_album_art = bundle.getString(MediaMetadata.METADATA_KEY_ALBUM_ART_URI); - String uri_icon = bundle.getString(MediaMetadata.METADATA_KEY_DISPLAY_ICON_URI); + String uri_art = null; + String uri_album_art = null; + String uri_icon = null; Bitmap bmp_art = bundle.getParcelable(MediaMetadata.METADATA_KEY_ART); Bitmap bmp_album_art = bundle.getParcelable(MediaMetadata.METADATA_KEY_ALBUM_ART); Bitmap bmp_icon = bundle.getParcelable(MediaMetadata.METADATA_KEY_DISPLAY_ICON); + if (mContext != null && Util.areUriImagesSupported(mContext)) { + uri_art = bundle.getString(MediaMetadata.METADATA_KEY_ART_URI); + uri_album_art = bundle.getString(MediaMetadata.METADATA_KEY_ALBUM_ART_URI); + uri_icon = bundle.getString(MediaMetadata.METADATA_KEY_DISPLAY_ICON_URI); + } + if (bmp_art != null) { setImage(bmp_art); } else if (bmp_album_art != null) { diff --git a/android/app/src/com/android/bluetooth/avrcp/AvrcpCoverArtService.java b/android/app/src/com/android/bluetooth/avrcp/AvrcpCoverArtService.java index 4397bbc876..8fde670b83 100644 --- a/android/app/src/com/android/bluetooth/avrcp/AvrcpCoverArtService.java +++ b/android/app/src/com/android/bluetooth/avrcp/AvrcpCoverArtService.java @@ -35,8 +35,8 @@ import javax.obex.ServerSession; /** * The AVRCP Cover Art Service * - * This service handles allocation of image handles and storage of images. It also owns the BIP OBEX - * server that handles requests to get AVRCP cover artwork. + * This service handles allocation of image handles and storage of images. It also owns the + * BIP OBEX server that handles requests to get AVRCP cover artwork. */ public class AvrcpCoverArtService { private static final String TAG = "AvrcpCoverArtService"; @@ -44,6 +44,12 @@ public class AvrcpCoverArtService { private static final int COVER_ART_STORAGE_MAX_ITEMS = 32; + /** + * Limiting transmit packet size because some carkits are disconnected if + * AVRCP Cover Art OBEX packet size exceed 1024 bytes. + */ + private static final int MAX_TRANSMIT_PACKET_SIZE = 1024; + private final Context mContext; // Cover Art and Image Handle objects @@ -207,7 +213,10 @@ public class AvrcpCoverArtService { disconnect(device); } }); - BluetoothObexTransport transport = new BluetoothObexTransport(socket); + BluetoothObexTransport transport = new BluetoothObexTransport(socket, + MAX_TRANSMIT_PACKET_SIZE, + BluetoothObexTransport.PACKET_SIZE_UNSPECIFIED); + transport.setConnectionForCoverArt(true); try { ServerSession session = new ServerSession(transport, s, null); mClients.put(device, session); diff --git a/android/app/src/com/android/bluetooth/btservice/AdapterState.java b/android/app/src/com/android/bluetooth/btservice/AdapterState.java index 7216d787c2..f25b3a2459 100644 --- a/android/app/src/com/android/bluetooth/btservice/AdapterState.java +++ b/android/app/src/com/android/bluetooth/btservice/AdapterState.java @@ -78,7 +78,7 @@ final class AdapterState extends StateMachine { "ro.bluetooth.ble_stop_timeout_delay"; static final int BLE_START_TIMEOUT_DELAY = 4000; - static final int BLE_STOP_TIMEOUT_DELAY = 1000; + static final int BLE_STOP_TIMEOUT_DELAY = 4000; static final int BREDR_START_TIMEOUT_DELAY = 4000; static final int BREDR_STOP_TIMEOUT_DELAY = 4000; diff --git a/android/app/src/com/android/bluetooth/hfp/BluetoothHeadsetProxy.java b/android/app/src/com/android/bluetooth/hfp/BluetoothHeadsetProxy.java index 824955d5a4..429ee7d0b8 100644 --- a/android/app/src/com/android/bluetooth/hfp/BluetoothHeadsetProxy.java +++ b/android/app/src/com/android/bluetooth/hfp/BluetoothHeadsetProxy.java @@ -16,8 +16,12 @@ package com.android.bluetooth.hfp; +import android.bluetooth.BluetoothAdapter; import android.bluetooth.BluetoothDevice; import android.bluetooth.BluetoothHeadset; +import android.bluetooth.BluetoothManager; +import android.bluetooth.BluetoothProfile; +import android.content.Context; import java.util.List; @@ -36,6 +40,14 @@ public class BluetoothHeadsetProxy { mBluetoothHeadset = headset; } + public void closeBluetoothHeadsetProxy(Context context) { + final BluetoothManager btManager = + context.getSystemService(BluetoothManager.class); + if (btManager != null) { + btManager.getAdapter().closeProfileProxy(BluetoothProfile.HEADSET, mBluetoothHeadset); + } + } + public void clccResponse(int index, int direction, int status, int mode, boolean mpty, String number, int type) { diff --git a/android/app/src/com/android/bluetooth/telephony/BluetoothInCallService.java b/android/app/src/com/android/bluetooth/telephony/BluetoothInCallService.java index dacfa069a5..5ca6397798 100644 --- a/android/app/src/com/android/bluetooth/telephony/BluetoothInCallService.java +++ b/android/app/src/com/android/bluetooth/telephony/BluetoothInCallService.java @@ -170,6 +170,8 @@ public class BluetoothInCallService extends InCallService { Log.d(TAG, "Bluetooth Adapter state: " + state); if (state == BluetoothAdapter.STATE_ON) { queryPhoneState(); + } else if (state == BluetoothAdapter.STATE_TURNING_OFF) { + clear(); } } } @@ -620,6 +622,12 @@ public class BluetoothInCallService extends InCallService { @Override public void onDestroy() { Log.d(TAG, "onDestroy"); + clear(); + super.onDestroy(); + } + + private void clear() { + Log.d(TAG, "clear"); if (mBluetoothOnModeChangedListener != null) { mAudioManager.removeOnModeChangedListener(mBluetoothOnModeChangedListener); mBluetoothOnModeChangedListener = null; @@ -628,8 +636,15 @@ public class BluetoothInCallService extends InCallService { unregisterReceiver(mBluetoothAdapterReceiver); mBluetoothAdapterReceiver = null; } + if (mBluetoothHeadset != null) { + mBluetoothHeadset.closeBluetoothHeadsetProxy(this); + mBluetoothHeadset = null; + } + mProfileListener = null; sInstance = null; - super.onDestroy(); + mCallbacks.clear(); + mBluetoothCallHashMap.clear(); + mClccIndexMap.clear(); } private void sendListOfCalls(boolean shouldLog) { diff --git a/android/app/tests/unit/src/com/android/bluetooth/audio_util/ImageTest.java b/android/app/tests/unit/src/com/android/bluetooth/audio_util/ImageTest.java index 89bbf5cbae..352fb7e359 100644 --- a/android/app/tests/unit/src/com/android/bluetooth/audio_util/ImageTest.java +++ b/android/app/tests/unit/src/com/android/bluetooth/audio_util/ImageTest.java @@ -38,6 +38,8 @@ import android.test.mock.MockContentResolver; import androidx.test.InstrumentationRegistry; import androidx.test.runner.AndroidJUnit4; +import com.android.bluetooth.R; + import org.junit.After; import org.junit.Before; import org.junit.Test; @@ -52,6 +54,7 @@ public class ImageTest { private Context mTargetContext; private @Mock Context mMockContext; + private @Mock Resources mMockResources; private Resources mTestResources; private MockContentResolver mTestContentResolver; @@ -104,6 +107,8 @@ public class ImageTest { }); when(mMockContext.getContentResolver()).thenReturn(mTestContentResolver); + when(mMockContext.getResources()).thenReturn(mMockResources); + when(mMockResources.getBoolean(R.bool.avrcp_target_cover_art_uri_images)).thenReturn(true); } @After @@ -270,6 +275,55 @@ public class ImageTest { } /** + * Make sure no image is set when you create an Image from a MediaMetadata object that contains + * cover artwork as an Art Uri and Bluetooth is not configured to support URI images. + */ + @Test + public void testCreateImageFromMediaMetadataWithArtUriDisabled() { + when(mMockResources.getBoolean(R.bool.avrcp_target_cover_art_uri_images)) + .thenReturn(false); + MediaMetadata metadata = + getMediaMetadataWithUri(MediaMetadata.METADATA_KEY_ART_URI, IMAGE_STRING_1); + Image artwork = new Image(mMockContext, metadata); + assertThat(artwork.getImage()).isNull(); + assertThat(artwork.getSource()).isEqualTo(Image.SOURCE_NONE); + assertThat(artwork.getImageHandle()).isNull(); + } + + /** + * Make sure no image is set when you create an Image from a MediaMetadata object that contains + * cover artwork as an Album Art Uri and Bluetooth is not configured to support URI images. + */ + @Test + public void testCreateImageFromMediaMetadataWithAlbumArtUriDisabled() { + when(mMockResources.getBoolean(R.bool.avrcp_target_cover_art_uri_images)) + .thenReturn(false); + MediaMetadata metadata = + getMediaMetadataWithUri(MediaMetadata.METADATA_KEY_ALBUM_ART_URI, IMAGE_STRING_1); + Image artwork = new Image(mMockContext, metadata); + assertThat(artwork.getImage()).isNull(); + assertThat(artwork.getSource()).isEqualTo(Image.SOURCE_NONE); + assertThat(artwork.getImageHandle()).isNull(); + } + + /** + * Make sure no image is set when you create an Image from a MediaMetadata object that contains + * cover artwork as a Display Icon Uri and Bluetooth is not configured to support URI images. + */ + @Test + public void testCreateImageFromMediaMetadataWithDisplayIconUriDisabled() { + when(mMockResources.getBoolean(R.bool.avrcp_target_cover_art_uri_images)) + .thenReturn(false); + MediaMetadata metadata = + getMediaMetadataWithUri(MediaMetadata.METADATA_KEY_DISPLAY_ICON_URI, + IMAGE_STRING_1); + Image artwork = new Image(mMockContext, metadata); + assertThat(artwork.getImage()).isNull(); + assertThat(artwork.getSource()).isEqualTo(Image.SOURCE_NONE); + assertThat(artwork.getImageHandle()).isNull(); + } + + /** * Make sure you can create an Image from a MediaMetadata object that contains no cover artwork */ @Test @@ -398,6 +452,52 @@ public class ImageTest { } /** + * Make sure no image is set when you create an Image from a Bundle that contains cover artwork + * as an Art Uri and Bluetooth is not configured to support URI images. + */ + @Test + public void testCreateImageFromBundleWithArtUriDisabled() { + when(mMockResources.getBoolean(R.bool.avrcp_target_cover_art_uri_images)) + .thenReturn(false); + Bundle bundle = getBundleWithUri(MediaMetadata.METADATA_KEY_ART_URI, IMAGE_STRING_1); + Image artwork = new Image(mMockContext, bundle); + assertThat(artwork.getImage()).isNull(); + assertThat(artwork.getSource()).isEqualTo(Image.SOURCE_NONE); + assertThat(artwork.getImageHandle()).isNull(); + } + + /** + * Make sure no image is set when you create an Image from a Bundle that contains cover artwork + * as an Album Art Uri and Bluetooth is not configured to support URI images. + */ + @Test + public void testCreateImageFromBundleWithAlbumArtUriDisabled() { + when(mMockResources.getBoolean(R.bool.avrcp_target_cover_art_uri_images)) + .thenReturn(false); + Bundle bundle = getBundleWithUri(MediaMetadata.METADATA_KEY_ALBUM_ART_URI, IMAGE_STRING_1); + Image artwork = new Image(mMockContext, bundle); + assertThat(artwork.getImage()).isNull(); + assertThat(artwork.getSource()).isEqualTo(Image.SOURCE_NONE); + assertThat(artwork.getImageHandle()).isNull(); + } + + /** + * Make sure no image is set when you create an Image from a Bundle that contains cover artwork + * as a Display Icon Uri and Bluetooth is not configured to support URI images. + */ + @Test + public void testCreateImageFromBundleWithDisplayIconUriDisabled() { + when(mMockResources.getBoolean(R.bool.avrcp_target_cover_art_uri_images)) + .thenReturn(false); + Bundle bundle = + getBundleWithUri(MediaMetadata.METADATA_KEY_DISPLAY_ICON_URI, IMAGE_STRING_1); + Image artwork = new Image(mMockContext, bundle); + assertThat(artwork.getImage()).isNull(); + assertThat(artwork.getSource()).isEqualTo(Image.SOURCE_NONE); + assertThat(artwork.getImageHandle()).isNull(); + } + + /** * Make sure you can create an Image from a Bundle that contains no cover artwork */ @Test diff --git a/system/audio_hal_interface/a2dp_encoding.cc b/system/audio_hal_interface/a2dp_encoding.cc index 8217ff1e22..9ec6c49481 100644 --- a/system/audio_hal_interface/a2dp_encoding.cc +++ b/system/audio_hal_interface/a2dp_encoding.cc @@ -163,6 +163,8 @@ class A2dpTransport } } + void SinkMetadataChanged(const sink_metadata_t&) override {} + tA2DP_CTRL_CMD GetPendingCmd() const { return a2dp_pending_cmd_; } void ResetPendingCmd() { a2dp_pending_cmd_ = A2DP_CTRL_CMD_NONE; } diff --git a/system/audio_hal_interface/client_interface.cc b/system/audio_hal_interface/client_interface.cc index fb2c532903..0b51d85a34 100644 --- a/system/audio_hal_interface/client_interface.cc +++ b/system/audio_hal_interface/client_interface.cc @@ -161,7 +161,18 @@ class BluetoothAudioPortImpl : public IBluetoothAudioPort { Return<void> updateSinkMetadata(const SinkMetadata& sinkMetadata) override { StopWatchLegacy stop_watch(__func__); LOG(INFO) << __func__ << ": " << sinkMetadata.tracks.size() << " track(s)"; - // TODO: pass the metadata up to transport_instance and LE Audio + // refer to StreamIn.impl.h within Audio HAL (AUDIO_HAL_VERSION_5_0) + std::vector<record_track_metadata> metadata_vec; + metadata_vec.reserve(sinkMetadata.tracks.size()); + for (const auto& metadata : sinkMetadata.tracks) { + metadata_vec.push_back({ + .source = static_cast<audio_source_t>(metadata.source), + .gain = metadata.gain, + }); + } + const sink_metadata_t sink_metadata = {.track_count = metadata_vec.size(), + .tracks = metadata_vec.data()}; + transport_instance_->SinkMetadataChanged(sink_metadata); return Void(); } diff --git a/system/audio_hal_interface/client_interface.h b/system/audio_hal_interface/client_interface.h index 795100b2d1..12e9878d8a 100644 --- a/system/audio_hal_interface/client_interface.h +++ b/system/audio_hal_interface/client_interface.h @@ -155,6 +155,7 @@ class IBluetoothTransportInstance { timespec* data_position) = 0; virtual void MetadataChanged(const source_metadata_t& source_metadata) = 0; + virtual void SinkMetadataChanged(const sink_metadata_t& sink_metadata) = 0; // Invoked when the transport is requested to reset presentation position virtual void ResetPresentationPosition() = 0; diff --git a/system/audio_hal_interface/client_interface_unittest.cc b/system/audio_hal_interface/client_interface_unittest.cc index bf3d6a6a47..423203fe7d 100644 --- a/system/audio_hal_interface/client_interface_unittest.cc +++ b/system/audio_hal_interface/client_interface_unittest.cc @@ -162,6 +162,8 @@ class TestSinkTransport } void MetadataChanged( const source_metadata_t& source_metadata __unused) override {} + void SinkMetadataChanged( + const sink_metadata_t& sink_metadata __unused) override {} void ResetPresentationPosition() override{}; void LogBytesRead(size_t bytes_readed __unused) override{}; }; @@ -200,6 +202,8 @@ class TestSourceTransport } void MetadataChanged( const source_metadata_t& source_metadata __unused) override {} + void SinkMetadataChanged( + const sink_metadata_t& sink_metadata __unused) override {} void ResetPresentationPosition() override{}; void LogBytesWritten(size_t bytes_written __unused) override{}; }; diff --git a/system/audio_hal_interface/hearing_aid_software_encoding.cc b/system/audio_hal_interface/hearing_aid_software_encoding.cc index d2d4496ac6..aa405f6e20 100644 --- a/system/audio_hal_interface/hearing_aid_software_encoding.cc +++ b/system/audio_hal_interface/hearing_aid_software_encoding.cc @@ -106,6 +106,8 @@ class HearingAidTransport } } + void SinkMetadataChanged(const sink_metadata_t&) override {} + void ResetPresentationPosition() override { VLOG(2) << __func__ << ": called."; remote_delay_report_ms_ = 0; diff --git a/system/audio_hal_interface/le_audio_software.cc b/system/audio_hal_interface/le_audio_software.cc index 384518254b..795a0df410 100644 --- a/system/audio_hal_interface/le_audio_software.cc +++ b/system/audio_hal_interface/le_audio_software.cc @@ -119,6 +119,18 @@ class LeAudioTransport { stream_cb_.on_metadata_update_(source_metadata); } + void SinkMetadataChanged(const sink_metadata_t& sink_metadata) { + auto track_count = sink_metadata.track_count; + + if (track_count == 0) { + LOG(WARNING) << ", invalid number of metadata changed tracks"; + return; + } + + if (stream_cb_.on_sink_metadata_update_) + stream_cb_.on_sink_metadata_update_(sink_metadata); + } + void ResetPresentationPosition() { VLOG(2) << __func__ << ": called."; remote_delay_report_ms_ = 0; @@ -206,6 +218,10 @@ class LeAudioSinkTransport transport_->MetadataChanged(source_metadata); } + void SinkMetadataChanged(const sink_metadata_t& sink_metadata) override { + transport_->SinkMetadataChanged(sink_metadata); + } + void ResetPresentationPosition() override { transport_->ResetPresentationPosition(); } @@ -279,6 +295,10 @@ class LeAudioSourceTransport transport_->MetadataChanged(source_metadata); } + void SinkMetadataChanged(const sink_metadata_t& sink_metadata) override { + transport_->SinkMetadataChanged(sink_metadata); + } + void ResetPresentationPosition() override { transport_->ResetPresentationPosition(); } diff --git a/system/audio_hal_interface/le_audio_software.h b/system/audio_hal_interface/le_audio_software.h index d595e6d673..e881a4c96d 100644 --- a/system/audio_hal_interface/le_audio_software.h +++ b/system/audio_hal_interface/le_audio_software.h @@ -44,6 +44,7 @@ struct StreamCallbacks { std::function<bool(bool start_media_task)> on_resume_; std::function<bool(void)> on_suspend_; std::function<bool(const source_metadata_t&)> on_metadata_update_; + std::function<bool(const sink_metadata_t&)> on_sink_metadata_update_; }; class LeAudioClientInterface { diff --git a/system/bta/le_audio/client_audio.cc b/system/bta/le_audio/client_audio.cc index baa4f6cf12..98cb14214f 100644 --- a/system/bta/le_audio/client_audio.cc +++ b/system/bta/le_audio/client_audio.cc @@ -245,6 +245,12 @@ bool le_audio_sink_on_metadata_update_req( return false; } +bool le_audio_source_on_metadata_update_req( + const sink_metadata_t& sink_metadata) { + // TODO: update microphone configuration based on sink metadata + return true; +} + } // namespace bool LeAudioClientAudioSource::Start( @@ -331,6 +337,7 @@ const void* LeAudioClientAudioSource::Acquire() { .on_resume_ = le_audio_sink_on_resume_req, .on_suspend_ = le_audio_sink_on_suspend_req, .on_metadata_update_ = le_audio_sink_on_metadata_update_req, + .on_sink_metadata_update_ = le_audio_source_on_metadata_update_req, }; sinkClientInterface = @@ -492,6 +499,7 @@ const void* LeAudioClientAudioSink::Acquire() { auto source_stream_cb = bluetooth::audio::le_audio::StreamCallbacks{ .on_resume_ = le_audio_source_on_resume_req, .on_suspend_ = le_audio_source_on_suspend_req, + .on_sink_metadata_update_ = le_audio_source_on_metadata_update_req, }; sourceClientInterface = diff --git a/system/bta/pan/bta_pan_ci.cc b/system/bta/pan/bta_pan_ci.cc index 00b218782d..9afe539fa9 100644 --- a/system/bta/pan/bta_pan_ci.cc +++ b/system/bta/pan/bta_pan_ci.cc @@ -26,8 +26,12 @@ #include "bta/pan/bta_pan_int.h" #include "osi/include/allocator.h" #include "stack/include/bt_hdr.h" +#include "stack/include/btu.h" #include "types/raw_address.h" +void bta_pan_sm_execute(tBTA_PAN_SCB* p_scb, uint16_t event, + tBTA_PAN_DATA* p_data); + /******************************************************************************* * * Function bta_pan_ci_tx_ready |