Disable AVRCP position change in silence mode
* Save the silence mode information in BtifAvPeer send from
JAVA, which helps AVRCP devices to check whether device
silence mode is enabled or not.
* Stop sending AVRCP position change event to remote when
silence mode is enabled.
Bug: 112323989
Test: Manual
Change-Id: I99d88a31caea062790c4ff0dc9199ed82f058067
diff --git a/binder/android/bluetooth/IBluetooth.aidl b/binder/android/bluetooth/IBluetooth.aidl
index 40a2db4..cc4c9cf 100644
--- a/binder/android/bluetooth/IBluetooth.aidl
+++ b/binder/android/bluetooth/IBluetooth.aidl
@@ -94,6 +94,8 @@
boolean setPairingConfirmation(in BluetoothDevice device, boolean accept);
int getPhonebookAccessPermission(in BluetoothDevice device);
+ boolean setSilenceMode(in BluetoothDevice device, boolean silence);
+ boolean getSilenceMode(in BluetoothDevice device);
boolean setPhonebookAccessPermission(in BluetoothDevice device, int value);
int getMessageAccessPermission(in BluetoothDevice device);
boolean setMessageAccessPermission(in BluetoothDevice device, int value);
diff --git a/btif/avrcp/avrcp_service.cc b/btif/avrcp/avrcp_service.cc
index bd09fa5..0603687 100644
--- a/btif/avrcp/avrcp_service.cc
+++ b/btif/avrcp/avrcp_service.cc
@@ -52,6 +52,10 @@
class A2dpInterfaceImpl : public A2dpInterface {
RawAddress active_peer() override { return btif_av_source_active_peer(); }
+
+ bool is_peer_in_silence_mode(const RawAddress& peer_address) override {
+ return btif_av_is_peer_silenced(peer_address);
+ }
} a2dp_interface_;
class AvrcpInterfaceImpl : public AvrcpInterface {
diff --git a/btif/include/btif_av.h b/btif/include/btif_av.h
index 370d5f1..e42f056 100644
--- a/btif/include/btif_av.h
+++ b/btif/include/btif_av.h
@@ -186,4 +186,13 @@
* @param none
*/
bool btif_av_is_a2dp_offload_enabled(void);
+
+/**
+ * Check whether peer device is silenced
+ *
+ * @param peer_address to check
+ *
+ */
+bool btif_av_is_peer_silenced(const RawAddress& peer_address);
+
#endif /* BTIF_AV_H */
diff --git a/btif/src/btif_av.cc b/btif/src/btif_av.cc
index 818abcf..b004f44 100644
--- a/btif/src/btif_av.cc
+++ b/btif/src/btif_av.cc
@@ -276,6 +276,9 @@
bool IsConnected() const;
bool IsStreaming() const;
+ bool IsInSilenceMode() const { return is_silenced_; };
+
+ void SetSilence(bool silence) { is_silenced_ = silence; };
/**
* Check whether any of the flags specified by the bitlags mask is set.
@@ -324,6 +327,7 @@
tBTA_AV_EDR edr_;
uint8_t flags_;
bool self_initiated_connection_;
+ bool is_silenced_;
};
class BtifAvSource {
@@ -385,6 +389,54 @@
const RawAddress& ActivePeer() const { return active_peer_; }
/**
+ * Check whether peer is silenced
+ *
+ * @param peer_address the peer to check
+ * @return true on silence mode enabled, otherwise false
+ */
+ bool IsPeerSilenced(const RawAddress& peer_address) {
+ if (peer_address.IsEmpty()) {
+ return false;
+ }
+ BtifAvPeer* peer = FindPeer(peer_address);
+ if (peer == nullptr) {
+ BTIF_TRACE_WARNING("%s: peer is null", __func__);
+ return false;
+ }
+ if (!peer->IsConnected()) {
+ BTIF_TRACE_WARNING("%s: peer is not connected", __func__);
+ return false;
+ }
+ return peer->IsInSilenceMode();
+ }
+
+ /**
+ * Set peer silence mode
+ *
+ * @param peer_address the peer to set
+ * @param silence true on enable silence mode, false on disable
+ * @return true on success, otherwise false
+ */
+ bool SetSilencePeer(const RawAddress& peer_address, const bool silence) {
+ if (peer_address.IsEmpty()) {
+ return false;
+ }
+ LOG_INFO(LOG_TAG, "%s: peer: %s", __PRETTY_FUNCTION__,
+ peer_address.ToString().c_str());
+ BtifAvPeer* peer = FindPeer(peer_address);
+ if (peer == nullptr) {
+ BTIF_TRACE_WARNING("%s: peer is null", __func__);
+ return false;
+ }
+ if (!peer->IsConnected()) {
+ BTIF_TRACE_WARNING("%s: peer is not connected", __func__);
+ return false;
+ }
+ peer->SetSilence(silence);
+ return true;
+ }
+
+ /**
* Set the active peer.
*
* @param peer_address the active peer address or RawAddress::kEmpty to
@@ -463,6 +515,7 @@
bool a2dp_offload_enabled_;
int max_connected_peers_;
std::map<RawAddress, BtifAvPeer*> peers_;
+ std::set<RawAddress> silenced_peers_;
RawAddress active_peer_;
std::map<uint8_t, tBTA_AV_HNDL> peer_id2bta_handle_;
};
@@ -829,6 +882,7 @@
bt_status_t BtifAvPeer::Init() {
alarm_free(av_open_on_rc_timer_);
av_open_on_rc_timer_ = alarm_new("btif_av_peer.av_open_on_rc_timer");
+ is_silenced_ = false;
state_machine_.Start();
return BT_STATUS_SUCCESS;
@@ -2586,6 +2640,16 @@
return BT_STATUS_SUCCESS;
}
+static void set_source_silence_peer_int(const RawAddress& peer_address,
+ bool silence) {
+ BTIF_TRACE_EVENT("%s: peer_address=%s, silence=%s", __func__,
+ peer_address.ToString().c_str(), silence ? "true" : "false");
+ if (!btif_av_source.SetSilencePeer(peer_address, silence)) {
+ BTIF_TRACE_ERROR("%s: Error setting silence state to %s", __func__,
+ peer_address.ToString().c_str());
+ }
+}
+
// Set the active peer
static void set_active_peer_int(uint8_t peer_sep,
const RawAddress& peer_address) {
@@ -2672,6 +2736,18 @@
peer_address, kBtaHandleUnknown, btif_av_event));
}
+static bt_status_t src_set_silence_sink(const RawAddress& peer_address,
+ bool silence) {
+ BTIF_TRACE_EVENT("%s: Peer %s", __func__, peer_address.ToString().c_str());
+ if (!btif_av_source.Enabled()) {
+ BTIF_TRACE_WARNING("%s: BTIF AV Source is not enabled", __func__);
+ return BT_STATUS_NOT_READY;
+ }
+
+ return do_in_main_thread(FROM_HERE, base::Bind(&set_source_silence_peer_int,
+ peer_address, silence));
+}
+
static bt_status_t src_set_active_sink(const RawAddress& peer_address) {
BTIF_TRACE_EVENT("%s: Peer %s", __func__, peer_address.ToString().c_str());
@@ -2718,6 +2794,7 @@
init_src,
src_connect_sink,
src_disconnect_sink,
+ src_set_silence_sink,
src_set_active_sink,
codec_config_src,
cleanup_src,
@@ -3097,3 +3174,7 @@
bool btif_av_is_a2dp_offload_enabled() {
return btif_av_source.A2dpOffloadEnabled();
}
+
+bool btif_av_is_peer_silenced(const RawAddress& peer_address) {
+ return btif_av_source.IsPeerSilenced(peer_address);
+}
diff --git a/include/hardware/bt_av.h b/include/hardware/bt_av.h
index 5cdf1c2..d38beaa 100644
--- a/include/hardware/bt_av.h
+++ b/include/hardware/bt_av.h
@@ -313,6 +313,9 @@
/** dis-connect from headset */
bt_status_t (*disconnect)(const RawAddress& bd_addr);
+ /** sets the connected device silence state */
+ bt_status_t (*set_silence_device)(const RawAddress& bd_addr, bool silence);
+
/** sets the connected device as active */
bt_status_t (*set_active_device)(const RawAddress& bd_addr);
diff --git a/profile/avrcp/avrcp_internal.h b/profile/avrcp/avrcp_internal.h
index c2e6549..4aeffdf 100644
--- a/profile/avrcp/avrcp_internal.h
+++ b/profile/avrcp/avrcp_internal.h
@@ -82,6 +82,7 @@
class A2dpInterface {
public:
virtual RawAddress active_peer() = 0;
+ virtual bool is_peer_in_silence_mode(const RawAddress& peer_address) = 0;
virtual ~A2dpInterface() = default;
-};
\ No newline at end of file
+};
diff --git a/profile/avrcp/device.cc b/profile/avrcp/device.cc
index c616d17..6956513 100644
--- a/profile/avrcp/device.cc
+++ b/profile/avrcp/device.cc
@@ -67,6 +67,10 @@
return address_ == a2dp_interface_->active_peer();
}
+bool Device::IsInSilenceMode() const {
+ return a2dp_interface_->is_peer_in_silence_mode(address_);
+}
+
void Device::VendorPacketHandler(uint8_t label,
std::shared_ptr<VendorPacket> pkt) {
CHECK(media_interface_);
@@ -466,7 +470,7 @@
// We still try to send updates while music is playing to the non active
// device even though the device thinks the music is paused. This makes
// the status bar on the remote device move.
- if (status.state == PlayState::PLAYING) {
+ if (status.state == PlayState::PLAYING && !IsInSilenceMode()) {
DEVICE_VLOG(0) << __func__ << ": Queue next play position update";
play_pos_update_cb_.Reset(base::Bind(&Device::HandlePlayPosUpdate,
weak_ptr_factory_.GetWeakPtr()));
@@ -1145,9 +1149,12 @@
}
void Device::SendMediaUpdate(bool metadata, bool play_status, bool queue) {
+ bool is_silence = IsInSilenceMode();
+
CHECK(media_interface_);
DEVICE_VLOG(4) << __func__ << ": Metadata=" << metadata
- << " : play_status= " << play_status << " : queue=" << queue;
+ << " : play_status= " << play_status << " : queue=" << queue
+ << " ; is_silence=" << is_silence;
if (queue) {
HandleNowPlayingUpdate();
@@ -1155,7 +1162,9 @@
if (play_status) {
HandlePlayStatusUpdate();
- HandlePlayPosUpdate();
+ if (!is_silence) {
+ HandlePlayPosUpdate();
+ }
}
if (metadata) HandleTrackUpdate();
diff --git a/profile/avrcp/device.h b/profile/avrcp/device.h
index 363f68d..e789706 100644
--- a/profile/avrcp/device.h
+++ b/profile/avrcp/device.h
@@ -75,6 +75,11 @@
bool Disconnect();
/**
+ * Returns true if the current device is silenced.
+ */
+ bool IsInSilenceMode() const;
+
+ /**
* Returns true if the current device is active.
*/
bool IsActive() const;
diff --git a/profile/avrcp/tests/avrcp_test_helper.h b/profile/avrcp/tests/avrcp_test_helper.h
index 16fc31f..edf3592 100644
--- a/profile/avrcp/tests/avrcp_test_helper.h
+++ b/profile/avrcp/tests/avrcp_test_helper.h
@@ -76,6 +76,7 @@
MOCK_METHOD1(event_open, void(const RawAddress&));
MOCK_METHOD1(event_close, void(const RawAddress&));
MOCK_METHOD0(active_peer, RawAddress());
+ MOCK_METHOD1(is_peer_in_silence_mode, bool(const RawAddress&));
};
class MockSdpInterface : public SdpInterface {