OSDN Git Service

Disable AVRCP position change in silence mode
authorUgo Yu <ugoyu@google.com>
Sat, 12 Jan 2019 19:12:30 +0000 (03:12 +0800)
committerUgo Yu <ugoyu@google.com>
Thu, 24 Jan 2019 00:44:08 +0000 (08:44 +0800)
* 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

binder/android/bluetooth/IBluetooth.aidl
btif/avrcp/avrcp_service.cc
btif/include/btif_av.h
btif/src/btif_av.cc
include/hardware/bt_av.h
profile/avrcp/avrcp_internal.h
profile/avrcp/device.cc
profile/avrcp/device.h
profile/avrcp/tests/avrcp_test_helper.h

index 40a2db4..cc4c9cf 100644 (file)
@@ -94,6 +94,8 @@ interface IBluetooth
     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);
index bd09fa5..0603687 100644 (file)
@@ -52,6 +52,10 @@ void do_in_avrcp_jni(const base::Closure& task) {
 
 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 {
index 370d5f1..e42f056 100644 (file)
@@ -186,4 +186,13 @@ void btif_av_src_disconnect_sink(const RawAddress& peer_address);
  *  @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 */
index 818abcf..b004f44 100644 (file)
@@ -276,6 +276,9 @@ class BtifAvPeer {
 
   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 @@ class BtifAvPeer {
   tBTA_AV_EDR edr_;
   uint8_t flags_;
   bool self_initiated_connection_;
+  bool is_silenced_;
 };
 
 class BtifAvSource {
@@ -385,6 +389,54 @@ class BtifAvSource {
   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 @@ class BtifAvSource {
   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 @@ std::string BtifAvPeer::FlagsToString() const {
 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 @@ static bt_status_t connect_int(RawAddress* peer_address, uint16_t uuid) {
   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 @@ static bt_status_t sink_disconnect_src(const RawAddress& peer_address) {
                             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 @@ static const btav_source_interface_t bt_av_src_interface = {
     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 @@ void btif_av_reset_audio_delay(void) { btif_a2dp_control_reset_audio_delay(); }
 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);
+}
index 5cdf1c2..d38beaa 100644 (file)
@@ -313,6 +313,9 @@ typedef struct {
   /** 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);
 
index c2e6549..4aeffdf 100644 (file)
@@ -82,6 +82,7 @@ class SdpInterface {
 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
+};
index c616d17..6956513 100644 (file)
@@ -67,6 +67,10 @@ bool Device::IsActive() const {
   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 @@ void Device::PlaybackPosNotificationResponse(uint8_t label, bool interim,
   // 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::SetBrowsedPlayerResponse(
 }
 
 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 @@ void Device::SendMediaUpdate(bool metadata, bool play_status, bool queue) {
 
   if (play_status) {
     HandlePlayStatusUpdate();
-    HandlePlayPosUpdate();
+    if (!is_silence) {
+      HandlePlayPosUpdate();
+    }
   }
 
   if (metadata) HandleTrackUpdate();
index 363f68d..e789706 100644 (file)
@@ -75,6 +75,11 @@ class Device {
   bool Disconnect();
 
   /**
+   * Returns true if the current device is silenced.
+   */
+  bool IsInSilenceMode() const;
+
+  /**
    * Returns true if the current device is active.
    */
   bool IsActive() const;
index 16fc31f..edf3592 100644 (file)
@@ -76,6 +76,7 @@ class MockA2dpInterface : public A2dpInterface {
   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 {