OSDN Git Service

Add AVRCP Browse packets to the completed packets.
authorAjay Panicker <apanicke@google.com>
Tue, 30 Jan 2018 18:36:45 +0000 (10:36 -0800)
committerAjay Panicker <apanicke@google.com>
Wed, 14 Feb 2018 01:30:16 +0000 (01:30 +0000)
Also add class representations for the following packet types:
  AVRCP Browse Packet
    AVRCP Change Path
    AVRCP Get Folder Items
    AVRCP Get Item Attributes
    AVRCP Set Browsed Player
    AVRCP Get Total Number of Items
    AVRCP Play Item

Bug: 68854188
Test: run host native test net_test_packets
Change-Id: I0bc682b11ec9181cfe1ed92678bb869ff3ef5740

53 files changed:
packet/Android.bp
packet/avrcp/Android.bp
packet/avrcp/avrcp_browse_packet.cc [new file with mode: 0644]
packet/avrcp/avrcp_browse_packet.h [new file with mode: 0644]
packet/avrcp/avrcp_common.h
packet/avrcp/avrcp_logging_helper.h
packet/avrcp/avrcp_packet.cc
packet/avrcp/avrcp_packet.h
packet/avrcp/avrcp_reject_packet.cc
packet/avrcp/capabilities_packet.cc
packet/avrcp/capabilities_packet.h
packet/avrcp/change_path.cc [new file with mode: 0644]
packet/avrcp/change_path.h [new file with mode: 0644]
packet/avrcp/get_element_attributes_packet.cc
packet/avrcp/get_element_attributes_packet.h
packet/avrcp/get_folder_items.cc [new file with mode: 0644]
packet/avrcp/get_folder_items.h [new file with mode: 0644]
packet/avrcp/get_item_attributes.cc [new file with mode: 0644]
packet/avrcp/get_item_attributes.h [new file with mode: 0644]
packet/avrcp/get_play_status_packet.cc
packet/avrcp/get_play_status_packet.h
packet/avrcp/get_total_number_of_items.cc [new file with mode: 0644]
packet/avrcp/get_total_number_of_items.h [new file with mode: 0644]
packet/avrcp/pass_through_packet.cc
packet/avrcp/pass_through_packet.h
packet/avrcp/play_item.cc [new file with mode: 0644]
packet/avrcp/play_item.h [new file with mode: 0644]
packet/avrcp/register_notification_packet.cc
packet/avrcp/register_notification_packet.h
packet/avrcp/set_browsed_player.cc [new file with mode: 0644]
packet/avrcp/set_browsed_player.h [new file with mode: 0644]
packet/avrcp/vendor_packet.cc
packet/avrcp/vendor_packet.h
packet/include/avrcp_packet.h
packet/tests/avrcp/avrcp_browse_packet_test.cc [new file with mode: 0644]
packet/tests/avrcp/avrcp_packet_test.cc
packet/tests/avrcp/avrcp_reject_packet_test.cc
packet/tests/avrcp/avrcp_test_packets.h
packet/tests/avrcp/change_path_packet_test.cc [new file with mode: 0644]
packet/tests/avrcp/get_capabilities_packet_test.cc
packet/tests/avrcp/get_element_attributes_packet_test.cc
packet/tests/avrcp/get_folder_items_packet_test.cc [new file with mode: 0644]
packet/tests/avrcp/get_item_attributes_packet_test.cc [new file with mode: 0644]
packet/tests/avrcp/get_play_status_packet_test.cc
packet/tests/avrcp/get_total_number_of_items_packet_test.cc [new file with mode: 0644]
packet/tests/avrcp/pass_through_packet_test.cc
packet/tests/avrcp/play_item_packet_test.cc [new file with mode: 0644]
packet/tests/avrcp/register_notification_packet_test.cc
packet/tests/avrcp/set_browsed_player_packet_test.cc [new file with mode: 0644]
packet/tests/avrcp/vendor_packet_test.cc
packet/tests/base/iterator_test.cc
packet/tests/base/packet_test.cc
test/run_host_unit_tests.py

index 2bcd5e0..ea0f2df 100644 (file)
@@ -18,21 +18,30 @@ cc_test {
     host_supported: true,
     local_include_dirs: ["tests"],
     srcs: [
-        "tests/base/packet_test.cc",
-        "tests/base/iterator_test.cc",
-        "tests/base/packet_builder_test.cc",
+        "tests/avrcp/avrcp_browse_packet_test.cc",
         "tests/avrcp/avrcp_packet_test.cc",
-        "tests/avrcp/vendor_packet_test.cc",
+        "tests/avrcp/avrcp_reject_packet_test.cc",
+        "tests/avrcp/change_path_packet_test.cc",
         "tests/avrcp/get_capabilities_packet_test.cc",
         "tests/avrcp/get_element_attributes_packet_test.cc",
+        "tests/avrcp/get_folder_items_packet_test.cc",
+        "tests/avrcp/get_item_attributes_packet_test.cc",
         "tests/avrcp/get_play_status_packet_test.cc",
+        "tests/avrcp/get_total_number_of_items_packet_test.cc",
         "tests/avrcp/pass_through_packet_test.cc",
+        "tests/avrcp/play_item_packet_test.cc",
         "tests/avrcp/register_notification_packet_test.cc",
-        "tests/avrcp/avrcp_reject_packet_test.cc",
+        "tests/avrcp/set_browsed_player_packet_test.cc",
+        "tests/avrcp/vendor_packet_test.cc",
+        "tests/base/iterator_test.cc",
+        "tests/base/packet_builder_test.cc",
+        "tests/base/packet_test.cc",
     ],
     static_libs: [
         "libgmock",
         "lib-bt-packets",
     ],
-    cflags: ["-DBUILDCFG","-g"],
+    cflags: [
+        "-DBUILDCFG",
+    ],
 }
index 8fb788b..e621449 100644 (file)
@@ -4,14 +4,21 @@ cc_library_static {
     export_include_dirs: ["."],
     host_supported: true,
     srcs: [
+        "avrcp_browse_packet.cc",
         "avrcp_packet.cc",
-        "vendor_packet.cc",
+        "avrcp_reject_packet.cc",
         "capabilities_packet.cc",
+        "change_path.cc",
         "get_element_attributes_packet.cc",
+        "get_folder_items.cc",
+        "get_item_attributes.cc",
         "get_play_status_packet.cc",
+        "get_total_number_of_items.cc",
         "pass_through_packet.cc",
+        "play_item.cc",
         "register_notification_packet.cc",
-        "avrcp_reject_packet.cc",
+        "set_browsed_player.cc",
+        "vendor_packet.cc",
     ],
     static_libs: [
         "lib-bt-packets-base",
diff --git a/packet/avrcp/avrcp_browse_packet.cc b/packet/avrcp/avrcp_browse_packet.cc
new file mode 100644 (file)
index 0000000..f4a7691
--- /dev/null
@@ -0,0 +1,91 @@
+/*
+ * Copyright 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "avrcp_browse_packet.h"
+
+#include <base/logging.h>
+
+namespace bluetooth {
+namespace avrcp {
+
+std::unique_ptr<BrowsePacketBuilder> BrowsePacketBuilder::MakeBuilder(
+    BrowsePdu pdu, std::unique_ptr<::bluetooth::PacketBuilder> payload) {
+  std::unique_ptr<BrowsePacketBuilder> builder =
+      std::unique_ptr<BrowsePacketBuilder>(new BrowsePacketBuilder(pdu));
+
+  builder->payload_ = std::move(payload);
+
+  return builder;
+}
+
+size_t BrowsePacketBuilder::size() const {
+  return BrowsePacket::kMinSize() + payload_->size();
+}
+
+bool BrowsePacketBuilder::Serialize(
+    const std::shared_ptr<::bluetooth::Packet>& pkt) {
+  ReserveSpace(pkt, size());
+
+  PushHeader(pkt, payload_->size());
+
+  return payload_->Serialize(pkt);
+}
+
+void BrowsePacketBuilder::PushHeader(
+    const std::shared_ptr<::bluetooth::Packet>& pkt, uint16_t length) {
+  AddPayloadOctets1(pkt, (uint8_t)pdu_);
+  AddPayloadOctets2(pkt, base::ByteSwap(length));
+}
+
+std::shared_ptr<BrowsePacket> BrowsePacket::Parse(
+    std::shared_ptr<::bluetooth::Packet> pkt) {
+  return std::shared_ptr<BrowsePacket>(new BrowsePacket(pkt));
+}
+
+BrowsePdu BrowsePacket::GetPdu() const {
+  return static_cast<BrowsePdu>(*begin());
+}
+
+uint16_t BrowsePacket::GetLength() const {
+  auto it = begin() + static_cast<size_t>(1);
+  return base::ByteSwap(it.extract<uint16_t>());
+}
+
+bool BrowsePacket::IsValid() const {
+  if (size() < kMinSize()) return false;
+  return size() == GetLength() + kMinSize();
+}
+
+std::string BrowsePacket::ToString() const {
+  std::stringstream ss;
+  ss << "AvrcpBrowsePacket: " << std::endl;
+  ss << "  └ PDU = " << GetPdu() << std::endl;
+  ss << "  └ Length = " << GetLength() << std::endl;
+  ss << "  └ Payload =";
+  for (auto it = begin() + static_cast<size_t>(3); it != end(); it++) {
+    ss << " " << loghex(*it);
+  }
+  ss << std::endl;
+
+  return ss.str();
+}
+
+std::pair<size_t, size_t> BrowsePacket::GetPayloadIndecies() const {
+  return std::pair<size_t, size_t>(packet_start_index_ + 3, packet_end_index_);
+}
+
+}  // namespace avrcp
+}  // namespace bluetooth
\ No newline at end of file
diff --git a/packet/avrcp/avrcp_browse_packet.h b/packet/avrcp/avrcp_browse_packet.h
new file mode 100644 (file)
index 0000000..f40deed
--- /dev/null
@@ -0,0 +1,84 @@
+/*
+ * Copyright 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <base/logging.h>
+#include <base/macros.h>
+#include <iostream>
+
+#include "iterator.h"
+#include "packet.h"
+#include "packet_builder.h"
+
+#include "avrcp_common.h"
+#include "avrcp_logging_helper.h"
+
+namespace bluetooth {
+namespace avrcp {
+
+class BrowsePacketBuilder : public ::bluetooth::PacketBuilder {
+ public:
+  virtual ~BrowsePacketBuilder() = default;
+
+  static std::unique_ptr<BrowsePacketBuilder> MakeBuilder(
+      BrowsePdu pdu, std::unique_ptr<::bluetooth::PacketBuilder> payload);
+
+  virtual size_t size() const override;
+  virtual bool Serialize(
+      const std::shared_ptr<::bluetooth::Packet>& pkt) override;
+
+ protected:
+  BrowsePdu pdu_;
+  std::unique_ptr<::bluetooth::PacketBuilder> payload_;
+
+  void PushHeader(const std::shared_ptr<::bluetooth::Packet>& pkt,
+                  uint16_t length);
+
+  BrowsePacketBuilder(BrowsePdu pdu) : pdu_(pdu){};
+};
+
+class BrowsePacket : public ::bluetooth::Packet {
+ public:
+  virtual ~BrowsePacket() = default;
+
+  static std::shared_ptr<BrowsePacket> Parse(
+      std::shared_ptr<::bluetooth::Packet> pkt);
+
+  /**
+   * Avrcp Browse Packet Layout
+   *   uint8_t pdu_;
+   *   uint16_t length_;
+   *   uint8_t[] payload_;
+   */
+  static constexpr size_t kMinSize() { return 3; }
+
+  BrowsePdu GetPdu() const;
+  uint16_t GetLength() const;
+
+  virtual bool IsValid() const override;
+  virtual std::string ToString() const override;
+
+ protected:
+  using ::bluetooth::Packet::Packet;
+
+ private:
+  virtual std::pair<size_t, size_t> GetPayloadIndecies() const;
+  DISALLOW_COPY_AND_ASSIGN(BrowsePacket);
+};
+
+}  // namespace avrcp
+}  // namespace bluetooth
\ No newline at end of file
index 9104920..40e2546 100644 (file)
@@ -18,6 +18,8 @@
 
 #include <base/sys_byteorder.h>
 
+#include <map>
+
 // This file contains the different AVRCP Constants
 namespace bluetooth {
 namespace avrcp {
@@ -50,6 +52,8 @@ enum class CommandPdu : uint8_t {
   GET_ELEMENT_ATTRIBUTES = 0x20,
   GET_PLAY_STATUS = 0x30,
   REGISTER_NOTIFICATION = 0x31,
+  SET_ADDRESSED_PLAYER = 0x60,
+  PLAY_ITEM = 0x74,
 };
 
 enum class PacketType : uint8_t {
@@ -76,42 +80,207 @@ enum class Event : uint8_t {
 
 enum class Attribute : uint32_t {
   TITLE = 0x01,
-  ARTIST_NAME,
-  ALBUM_NAME,
-  TRACK_NUMBER,
-  TOTAL_NUMBER_OF_TRACKS,
-  GENRE,
-  PLAYING_TIME,
-  DEFAULT_COVER_ART,
+  ARTIST_NAME = 0x02,
+  ALBUM_NAME = 0x03,
+  TRACK_NUMBER = 0x04,
+  TOTAL_NUMBER_OF_TRACKS = 0x05,
+  GENRE = 0x06,
+  PLAYING_TIME = 0x07,
+  DEFAULT_COVER_ART = 0x08,
 };
 
 enum class Status : uint8_t {
   INVALID_COMMAND = 0x00,
-  INVALID_PARAMETER,
-  PARAMETER_CONTENT_ERROR,
-  INTERNAL_ERROR,
-  NO_ERROR,
-  UIDS_CHANGED,
-  RESERVED,
-  INVALID_DIRECTION,
-  NOT_A_DIRECTORY,
-  DOES_NOT_EXIST,
-  INVALID_SCOPE,
-  RANGE_OUT_OF_BOUNDS,
-  FOLDER_ITEM_NOT_PLAYABLE,
-  MEDIA_IN_USE,
-  NOW_PLAYING_LIST_FULL,
-  SEARCH_NOT_SUPPORTED,
-  SEARCH_IN_PROGRESS,
-  INVALID_PLAYER_ID,
-  PLAYER_NOT_BROWSABLE,
-  PLAYER_NOT_ADDRESSED,
-  NO_VALID_SEARCH_RESULTS,
-  NO_AVAILABLE_PLAYERS,
-  ADDRESSED_PLAYER_CHANGED,
+  INVALID_PARAMETER = 0x01,
+  PARAMETER_CONTENT_ERROR = 0x02,
+  INTERNAL_ERROR = 0x03,
+  NO_ERROR = 0x04,
+  UIDS_CHANGED = 0x05,
+  RESERVED = 0x06,
+  INVALID_DIRECTION = 0x07,
+  NOT_A_DIRECTORY = 0x08,
+  DOES_NOT_EXIST = 0x09,
+  INVALID_SCOPE = 0x0a,
+  RANGE_OUT_OF_BOUNDS = 0xb,
+  FOLDER_ITEM_NOT_PLAYABLE = 0x0c,
+  MEDIA_IN_USE = 0x0d,
+  NOW_PLAYING_LIST_FULL = 0x0e,
+  SEARCH_NOT_SUPPORTED = 0x0f,
+  SEARCH_IN_PROGRESS = 0x10,
+  INVALID_PLAYER_ID = 0x11,
+  PLAYER_NOT_BROWSABLE = 0x12,
+  PLAYER_NOT_ADDRESSED = 0x13,
+  NO_VALID_SEARCH_RESULTS = 0x14,
+  NO_AVAILABLE_PLAYERS = 0x15,
+  ADDRESSED_PLAYER_CHANGED = 0x16,
+};
+
+enum class BrowsePdu : uint8_t {
+  SET_BROWSED_PLAYER = 0x70,
+  GET_FOLDER_ITEMS = 0x71,
+  CHANGE_PATH = 0x72,
+  GET_ITEM_ATTRIBUTES = 0x73,
+  GET_TOTAL_NUMBER_OF_ITEMS = 0x75,
+};
+
+enum class Scope : uint8_t {
+  MEDIA_PLAYER_LIST = 0x00,
+  VFS = 0x01,
+  SEARCH = 0x02,
+  NOW_PLAYING = 0x03,
+};
+
+enum class Direction : uint8_t {
+  UP = 0x00,
+  DOWN = 0x01,
 };
 
 using AttributeEntry = std::pair<Attribute, std::string>;
 
+struct MediaPlayerItem {
+  uint16_t id_;
+  std::string name_;
+  bool browsable_;
+
+  MediaPlayerItem(uint16_t id, std::string name, bool browsable)
+      : id_(id), name_(name), browsable_(browsable) {}
+
+  MediaPlayerItem(const MediaPlayerItem&) = default;
+
+  static size_t size(const MediaPlayerItem& item) {
+    size_t ret = 0;
+    ret += 1;   // Media Player Type
+    ret += 2;   // Item Length
+    ret += 2;   // Player Id
+    ret += 1;   // Player Type
+    ret += 4;   // Player Subtype
+    ret += 1;   // Play Status
+    ret += 16;  // Features
+    ret += 2;   // UTF-8 character set
+    ret += 2;   // Name Length
+    ret += item.name_.size();
+    return ret;
+  }
+};
+
+struct FolderItem {
+  uint64_t uid_;
+  uint8_t folder_type_;
+  bool is_playable_;
+  std::string name_;
+
+  FolderItem(uint64_t uid, uint8_t folder_type, bool is_playable,
+             const std::string& name)
+      : uid_(uid),
+        folder_type_(folder_type),
+        is_playable_(is_playable),
+        name_(name) {}
+
+  FolderItem(const FolderItem&) = default;
+
+  static size_t size(const FolderItem& item) {
+    size_t ret = 0;
+    ret += 1;  // Folder Item Type
+    ret += 2;  // Item Length
+    ret += 8;  // Folder UID
+    ret += 1;  // Folder Type
+    ret += 1;  // Is Playable byte
+    ret += 2;  // UTF-8 Character Set
+    ret += 2;  // Name Length
+    ret += item.name_.size();
+    return ret;
+  }
+};
+
+// NOTE: We never use media type field because we only support audio types
+struct MediaElementItem {
+  uint64_t uid_ = 0;
+  std::string name_;
+  std::map<Attribute, std::string> attributes_;
+
+  MediaElementItem(uint64_t uid, std::string name,
+                   std::map<Attribute, std::string> attributes)
+      : uid_(uid), name_(name), attributes_(attributes) {}
+
+  MediaElementItem(const MediaElementItem&) = default;
+
+  static size_t size(const MediaElementItem& item) {
+    size_t ret = 0;
+    ret += 1;  // Media Element Item Type
+    ret += 2;  // Item Length
+    ret += 8;  // Item UID
+    ret += 1;  // Media Type
+    ret += 2;  // UTF-8 Character Set
+    ret += 2;  // Name Length
+    ret += item.name_.size();
+    ret += 1;  // Number of Attributes
+    for (auto it = item.attributes_.begin(); it != item.attributes_.end();
+         it++) {
+      ret += 4;  // Attribute ID
+      ret += 2;  // UTF-8 Character Set
+      ret += 2;  // Attribute Length
+      ret += it->second.size();
+    }
+
+    return ret;
+  }
+};
+
+struct MediaListItem {
+  enum : uint8_t { PLAYER = 0x01, FOLDER = 0x02, SONG = 0x03 } type_;
+
+  union {
+    MediaPlayerItem player_;
+    FolderItem folder_;
+    MediaElementItem song_;
+  };
+
+  MediaListItem(MediaPlayerItem item) : type_(PLAYER), player_(item) {}
+
+  MediaListItem(FolderItem item) : type_(FOLDER), folder_(item) {}
+
+  MediaListItem(MediaElementItem item) : type_(SONG), song_(item) {}
+
+  MediaListItem(const MediaListItem& item) {
+    type_ = item.type_;
+    switch (item.type_) {
+      case PLAYER:
+        new (&player_) MediaPlayerItem(item.player_);
+        return;
+      case FOLDER:
+        new (&folder_) FolderItem(item.folder_);
+        return;
+      case SONG:
+        new (&song_) MediaElementItem(item.song_);
+        return;
+    }
+  }
+
+  ~MediaListItem() {
+    switch (type_) {
+      case PLAYER:
+        player_.~MediaPlayerItem();
+        return;
+      case FOLDER:
+        folder_.~FolderItem();
+        return;
+      case SONG:
+        song_.~MediaElementItem();
+        return;
+    }
+  }
+
+  static size_t size(const MediaListItem& item) {
+    switch (item.type_) {
+      case PLAYER:
+        return MediaPlayerItem::size(item.player_);
+      case FOLDER:
+        return FolderItem::size(item.folder_);
+      case SONG:
+        return MediaElementItem::size(item.song_);
+    }
+  }
+};
+
 }  // namespace avrcp
 }  // namespace bluetooth
\ No newline at end of file
index dee0466..f2f0b32 100644 (file)
@@ -83,6 +83,8 @@ inline std::string CommandPduText(const CommandPdu& pdu) {
     CASE_RETURN_TEXT(CommandPdu::GET_ELEMENT_ATTRIBUTES);
     CASE_RETURN_TEXT(CommandPdu::GET_PLAY_STATUS);
     CASE_RETURN_TEXT(CommandPdu::REGISTER_NOTIFICATION);
+    CASE_RETURN_TEXT(CommandPdu::SET_ADDRESSED_PLAYER);
+    CASE_RETURN_TEXT(CommandPdu::PLAY_ITEM);
     default:
       return "Unknown Command PDU: " + loghex(pdu);
   }
@@ -190,5 +192,48 @@ inline std::ostream& operator<<(std::ostream& os, const Status& status) {
   return os << StatusText(status);
 }
 
+inline std::string BrowsePduText(const BrowsePdu& pdu) {
+  switch (pdu) {
+    CASE_RETURN_TEXT(BrowsePdu::SET_BROWSED_PLAYER);
+    CASE_RETURN_TEXT(BrowsePdu::GET_FOLDER_ITEMS);
+    CASE_RETURN_TEXT(BrowsePdu::CHANGE_PATH);
+    CASE_RETURN_TEXT(BrowsePdu::GET_ITEM_ATTRIBUTES);
+    default:
+      return "Unknown Browse Pdu: " + loghex(pdu);
+  }
+}
+
+inline std::ostream& operator<<(std::ostream& os, const BrowsePdu& pdu) {
+  return os << BrowsePduText(pdu);
+}
+
+inline std::string ScopeText(const Scope& scope) {
+  switch (scope) {
+    CASE_RETURN_TEXT(Scope::MEDIA_PLAYER_LIST);
+    CASE_RETURN_TEXT(Scope::VFS);
+    CASE_RETURN_TEXT(Scope::SEARCH);
+    CASE_RETURN_TEXT(Scope::NOW_PLAYING);
+    default:
+      return "Unknown Scope: " + loghex(scope);
+  }
+}
+
+inline std::ostream& operator<<(std::ostream& os, const Scope& pdu) {
+  return os << ScopeText(pdu);
+}
+
+inline std::string DirectionText(const Direction& dir) {
+  switch (dir) {
+    CASE_RETURN_TEXT(Direction::UP);
+    CASE_RETURN_TEXT(Direction::DOWN);
+    default:
+      return "Unknown Direction: " + loghex(dir);
+  }
+}
+
+inline std::ostream& operator<<(std::ostream& os, const Direction& dir) {
+  return os << DirectionText(dir);
+}
+
 }  // namespace avrcp
 }  // namespace bluetooth
\ No newline at end of file
index 7068df6..635759a 100644 (file)
@@ -37,7 +37,7 @@ std::unique_ptr<PacketBuilder> PacketBuilder::MakeBuilder(
 
 size_t PacketBuilder::size() const {
   // The size of the header for an Packet is 3
-  return payload_->size() + Packet::kHeaderSize();
+  return payload_->size() + Packet::kMinSize();
 }
 
 bool PacketBuilder::Serialize(const std::shared_ptr<::bluetooth::Packet>& pkt) {
@@ -91,7 +91,7 @@ Opcode Packet::GetOpcode() const {
   return static_cast<Opcode>(value);
 }
 
-bool Packet::IsValid() const { return size() >= kHeaderSize(); }
+bool Packet::IsValid() const { return size() >= kMinSize(); }
 
 std::string Packet::ToString() const {
   std::stringstream ss;
index 8d7e8ff..1e56186 100644 (file)
@@ -78,7 +78,7 @@ class Packet : public ::bluetooth::Packet {
    *   Opcode opcode_;
    *   uint8_t[] payload_;
    */
-  static constexpr size_t kHeaderSize() { return 3; };
+  static constexpr size_t kMinSize() { return 3; };
 
   // Getter Functions
   CType GetCType() const;
index a7f98bd..d4ad7ad 100644 (file)
@@ -27,7 +27,7 @@ std::unique_ptr<RejectBuilder> RejectBuilder::MakeBuilder(CommandPdu pdu,
   return builder;
 }
 
-size_t RejectBuilder::size() const { return VendorPacket::kHeaderSize() + 1; }
+size_t RejectBuilder::size() const { return VendorPacket::kMinSize() + 1; }
 
 bool RejectBuilder::Serialize(const std::shared_ptr<::bluetooth::Packet>& pkt) {
   ReserveSpace(pkt, size());
index 6eba8a5..459b47d 100644 (file)
@@ -28,7 +28,7 @@ GetCapabilitiesRequestBuilder::MakeBuilder(Capability capability) {
 }
 
 size_t GetCapabilitiesRequestBuilder::size() const {
-  return GetCapabilitiesRequest::kHeaderSize();
+  return GetCapabilitiesRequest::kMinSize();
 }
 
 bool GetCapabilitiesRequestBuilder::Serialize(
@@ -46,13 +46,13 @@ bool GetCapabilitiesRequestBuilder::Serialize(
 }
 
 Capability GetCapabilitiesRequest::GetCapabilityRequested() const {
-  auto value = *(begin() + VendorPacket::kHeaderSize());
+  auto value = *(begin() + VendorPacket::kMinSize());
   return static_cast<Capability>(value);
 }
 
 bool GetCapabilitiesRequest::IsValid() const {
   if (!VendorPacket::IsValid()) return false;
-  return (size() == VendorPacket::kHeaderSize() + 1);
+  return (size() == VendorPacket::kMinSize() + 1);
 }
 
 std::string GetCapabilitiesRequest::ToString() const {
@@ -120,7 +120,7 @@ size_t GetCapabilitiesResponseBuilder::size() const {
   size_t capability_count = elements_.size();
   size_t capability_size = capability_ == Capability::COMPANY_ID ? 3 : 1;
 
-  return GetCapabilitiesResponse::kHeaderSize() +
+  return GetCapabilitiesResponse::kMinSize() +
          (capability_count * capability_size);
 }
 
@@ -132,7 +132,7 @@ bool GetCapabilitiesResponseBuilder::Serialize(
   PacketBuilder::PushHeader(pkt);
 
   // Push the avrcp vendor command headers
-  uint16_t parameter_count = size() - VendorPacket::kHeaderSize();
+  uint16_t parameter_count = size() - VendorPacket::kMinSize();
   VendorPacketBuilder::PushHeader(pkt, parameter_count);
 
   // Push the capability, capability count, and elements
index cc3d7d1..3a4607f 100644 (file)
@@ -62,9 +62,7 @@ class GetCapabilitiesRequest : public VendorPacket {
    *   GetCapabilitiesRequestPacket:
    *     uint8_t capability_requested:
    */
-  static constexpr size_t kHeaderSize() {
-    return VendorPacket::kHeaderSize() + 1;
-  };
+  static constexpr size_t kMinSize() { return VendorPacket::kMinSize() + 1; };
 
   // Getter Functions
   Capability GetCapabilityRequested() const;
@@ -126,9 +124,7 @@ class GetCapabilitiesResponse : public VendorPacket {
    *        uint8_t company_id[3];
    *     } capability_array[];
    */
-  static constexpr size_t kHeaderSize() {
-    return VendorPacket::kHeaderSize() + 2;
-  };
+  static constexpr size_t kMinSize() { return VendorPacket::kMinSize() + 2; };
 
   // TODO: Implement these for AVRCP Controller
   // virtual uint8_t GetCapabilityReturned() const;
diff --git a/packet/avrcp/change_path.cc b/packet/avrcp/change_path.cc
new file mode 100644 (file)
index 0000000..94bd237
--- /dev/null
@@ -0,0 +1,88 @@
+/*
+ * Copyright 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "change_path.h"
+
+namespace bluetooth {
+namespace avrcp {
+
+std::unique_ptr<ChangePathResponseBuilder>
+ChangePathResponseBuilder::MakeBuilder(Status status,
+                                       uint32_t num_items_in_folder) {
+  std::unique_ptr<ChangePathResponseBuilder> builder(
+      new ChangePathResponseBuilder(status, num_items_in_folder));
+
+  return builder;
+}
+
+size_t ChangePathResponseBuilder::size() const {
+  size_t len = BrowsePacket::kMinSize();
+  len += 1;  // Status
+  if (status_ != Status::NO_ERROR) return len;
+
+  len += 4;  // Number of items in folder
+  return len;
+}
+
+bool ChangePathResponseBuilder::Serialize(
+    const std::shared_ptr<::bluetooth::Packet>& pkt) {
+  ReserveSpace(pkt, size());
+
+  BrowsePacketBuilder::PushHeader(pkt, size() - BrowsePacket::kMinSize());
+
+  AddPayloadOctets1(pkt, (uint8_t)status_);
+  if (status_ != Status::NO_ERROR) return true;
+
+  AddPayloadOctets4(pkt, base::ByteSwap(num_items_in_folder_));
+  return true;
+}
+
+uint16_t ChangePathRequest::GetUidCounter() const {
+  auto it = begin() + BrowsePacket::kMinSize();
+  return base::ByteSwap(it.extract<uint16_t>());
+}
+
+Direction ChangePathRequest::GetDirection() const {
+  auto it = begin() + BrowsePacket::kMinSize() + static_cast<size_t>(2);
+  return static_cast<Direction>(*it);
+}
+
+uint64_t ChangePathRequest::GetUid() const {
+  auto it = begin() + BrowsePacket::kMinSize() + static_cast<size_t>(3);
+  return base::ByteSwap(it.extract<uint64_t>());
+}
+
+bool ChangePathRequest::IsValid() const {
+  if (!BrowsePacket::IsValid()) return false;
+  // Change path request packets are always the same size
+  return size() == kMinSize();
+}
+
+std::string ChangePathRequest::ToString() const {
+  std::stringstream ss;
+  ss << "ChangePathRequestPacket: " << std::endl;
+  ss << "  └ PDU = " << GetPdu() << std::endl;
+  ss << "  └ Length = " << GetLength() << std::endl;
+  ss << "  └ UID Counter = " << loghex(GetUidCounter()) << std::endl;
+  ss << "  └ Direction = " << GetDirection() << std::endl;
+  ss << "  └ UID Requested = " << loghex(GetUid()) << std::endl;
+  ss << std::endl;
+
+  return ss.str();
+}
+
+}  // namespace avrcp
+}  // namespace bluetooth
\ No newline at end of file
diff --git a/packet/avrcp/change_path.h b/packet/avrcp/change_path.h
new file mode 100644 (file)
index 0000000..12fae7e
--- /dev/null
@@ -0,0 +1,73 @@
+/*
+ * Copyright 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include "avrcp_browse_packet.h"
+
+namespace bluetooth {
+namespace avrcp {
+
+class ChangePathResponseBuilder : public BrowsePacketBuilder {
+ public:
+  virtual ~ChangePathResponseBuilder() = default;
+
+  static std::unique_ptr<ChangePathResponseBuilder> MakeBuilder(
+      Status status, uint32_t num_items_in_folder);
+
+  virtual size_t size() const override;
+  virtual bool Serialize(
+      const std::shared_ptr<::bluetooth::Packet>& pkt) override;
+
+ private:
+  Status status_;
+  uint32_t num_items_in_folder_;
+
+  ChangePathResponseBuilder(Status status, uint32_t num_items_in_folder)
+      : BrowsePacketBuilder(BrowsePdu::CHANGE_PATH),
+        status_(status),
+        num_items_in_folder_(num_items_in_folder) {}
+};
+
+class ChangePathRequest : public BrowsePacket {
+ public:
+  virtual ~ChangePathRequest() = default;
+
+  /**
+   * Avrcp Change Path Packet Layout
+   *   BrowsePacket:
+   *     uint8_t pdu_;
+   *     uint16_t length_;
+   *   ChangePathRequest:
+   *     uint16_t uid_counter_;
+   *     uint8_t direction_;
+   *     uint64_t folder_uid_;
+   */
+  static constexpr size_t kMinSize() { return BrowsePacket::kMinSize() + 11; }
+
+  uint16_t GetUidCounter() const;
+  Direction GetDirection() const;
+  uint64_t GetUid() const;
+
+  virtual bool IsValid() const override;
+  virtual std::string ToString() const override;
+
+ protected:
+  using BrowsePacket::BrowsePacket;
+};
+
+}  // namespace avrcp
+}  // namespace bluetooth
\ No newline at end of file
index 975bbe3..43b51ee 100644 (file)
@@ -22,18 +22,18 @@ namespace bluetooth {
 namespace avrcp {
 
 uint64_t GetElementAttributesRequest::GetIdentifier() const {
-  auto it = begin() + VendorPacket::kHeaderSize();
+  auto it = begin() + VendorPacket::kMinSize();
   return it.extract<uint64_t>();
 }
 
 uint8_t GetElementAttributesRequest::GetNumAttributes() const {
-  auto it = begin() + VendorPacket::kHeaderSize() + static_cast<size_t>(8);
+  auto it = begin() + VendorPacket::kMinSize() + static_cast<size_t>(8);
   return it.extract<uint8_t>();
 }
 
 std::vector<Attribute> GetElementAttributesRequest::GetAttributesRequested()
     const {
-  auto it = begin() + VendorPacket::kHeaderSize() + static_cast<size_t>(8);
+  auto it = begin() + VendorPacket::kMinSize() + static_cast<size_t>(8);
 
   size_t number_of_attributes = it.extract<uint8_t>();
 
@@ -48,11 +48,10 @@ std::vector<Attribute> GetElementAttributesRequest::GetAttributesRequested()
 
 bool GetElementAttributesRequest::IsValid() const {
   if (!VendorPacket::IsValid()) return false;
-  if (size() < kHeaderSize()) return false;
+  if (size() < kMinSize()) return false;
 
   size_t num_attributes = GetNumAttributes();
-  auto attr_start =
-      begin() + VendorPacket::kHeaderSize() + static_cast<size_t>(9);
+  auto attr_start = begin() + VendorPacket::kMinSize() + static_cast<size_t>(9);
 
   // Casting the int returned from end - attr_start should be fine. If an
   // overflow occurs we can definitly say the packet is invalid
@@ -117,7 +116,7 @@ size_t GetElementAttributesResponseBuilder::size() const {
     attr_list_size += attribute_entry.second.length();
   }
 
-  return VendorPacket::kHeaderSize() + 1 + attr_list_size;
+  return VendorPacket::kMinSize() + 1 + attr_list_size;
 }
 
 bool GetElementAttributesResponseBuilder::Serialize(
@@ -126,7 +125,7 @@ bool GetElementAttributesResponseBuilder::Serialize(
 
   PacketBuilder::PushHeader(pkt);
 
-  VendorPacketBuilder::PushHeader(pkt, size() - VendorPacket::kHeaderSize());
+  VendorPacketBuilder::PushHeader(pkt, size() - VendorPacket::kMinSize());
 
   AddPayloadOctets1(pkt, entries_.size());
   for (auto attribute_entry : entries_) {
index 72383ab..6f75b93 100644 (file)
@@ -43,9 +43,7 @@ class GetElementAttributesRequest : public VendorPacket {
    *     uint8_t number_of_attributes;
    *     uint32_t attributes_requested[];
    */
-  static constexpr size_t kHeaderSize() {
-    return VendorPacket::kHeaderSize() + 9;
-  }
+  static constexpr size_t kMinSize() { return VendorPacket::kMinSize() + 9; }
 
   // Getter Functions
   uint64_t GetIdentifier() const;
diff --git a/packet/avrcp/get_folder_items.cc b/packet/avrcp/get_folder_items.cc
new file mode 100644 (file)
index 0000000..5a267b1
--- /dev/null
@@ -0,0 +1,290 @@
+/*
+ * Copyright 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "get_folder_items.h"
+
+namespace bluetooth {
+namespace avrcp {
+
+std::unique_ptr<GetFolderItemsResponseBuilder>
+GetFolderItemsResponseBuilder::MakePlayerListBuilder(Status status,
+                                                     uint16_t uid_counter) {
+  std::unique_ptr<GetFolderItemsResponseBuilder> builder(
+      new GetFolderItemsResponseBuilder(Scope::MEDIA_PLAYER_LIST, status,
+                                        uid_counter));
+
+  return builder;
+}
+
+std::unique_ptr<GetFolderItemsResponseBuilder>
+GetFolderItemsResponseBuilder::MakeVFSBuilder(Status status,
+                                              uint16_t uid_counter) {
+  std::unique_ptr<GetFolderItemsResponseBuilder> builder(
+      new GetFolderItemsResponseBuilder(Scope::VFS, status, uid_counter));
+
+  return builder;
+}
+
+std::unique_ptr<GetFolderItemsResponseBuilder>
+GetFolderItemsResponseBuilder::MakeNowPlayingBuilder(Status status,
+                                                     uint16_t uid_counter) {
+  std::unique_ptr<GetFolderItemsResponseBuilder> builder(
+      new GetFolderItemsResponseBuilder(Scope::NOW_PLAYING, status,
+                                        uid_counter));
+
+  return builder;
+}
+
+size_t GetFolderItemsResponseBuilder::size() const {
+  size_t len = BrowsePacket::kMinSize();
+  len += 1;  // Status
+
+  // There is nothing other than the status in the packet if the status isn't
+  // NO_ERROR
+  if (status_ != Status::NO_ERROR || items_.size() == 0) return len;
+
+  len += 2;  // UID Counter
+  len += 2;  // Number of Items;
+  for (const auto& item : items_) {
+    len += MediaListItem::size(item);
+  }
+
+  return len;
+}
+
+bool GetFolderItemsResponseBuilder::Serialize(
+    const std::shared_ptr<::bluetooth::Packet>& pkt) {
+  ReserveSpace(pkt, size());
+
+  BrowsePacketBuilder::PushHeader(pkt, size() - BrowsePacket::kMinSize());
+
+  if (status_ == Status::NO_ERROR && items_.size() == 0) {
+    // Return range out of bounds if there are zero items in the folder
+    status_ = Status::RANGE_OUT_OF_BOUNDS;
+  }
+
+  AddPayloadOctets1(pkt, (uint8_t)status_);  // Status
+  if (status_ != Status::NO_ERROR) return true;
+
+  AddPayloadOctets2(pkt, base::ByteSwap(uid_counter_));
+  uint16_t num_items = items_.size();
+  AddPayloadOctets2(pkt, base::ByteSwap(num_items));
+
+  for (const auto& item : items_) {
+    PushMediaListItem(pkt, item);
+  }
+
+  return true;
+}
+
+void GetFolderItemsResponseBuilder::AddMediaPlayer(MediaPlayerItem item) {
+  CHECK(scope_ == Scope::MEDIA_PLAYER_LIST);
+  items_.push_back(MediaListItem(item));
+}
+
+void GetFolderItemsResponseBuilder::AddSong(MediaElementItem item) {
+  CHECK(scope_ == Scope::VFS || scope_ == Scope::NOW_PLAYING);
+  items_.push_back(MediaListItem(item));
+}
+
+void GetFolderItemsResponseBuilder::AddFolder(FolderItem item) {
+  CHECK(scope_ == Scope::VFS);
+  items_.push_back(MediaListItem(item));
+}
+
+void GetFolderItemsResponseBuilder::PushMediaListItem(
+    const std::shared_ptr<::bluetooth::Packet>& pkt,
+    const MediaListItem& item) {
+  switch (item.type_) {
+    case MediaListItem::PLAYER:
+      PushMediaPlayerItem(pkt, item.player_);
+      break;
+    case MediaListItem::FOLDER:
+      PushFolderItem(pkt, item.folder_);
+      break;
+    case MediaListItem::SONG:
+      PushMediaElementItem(pkt, item.song_);
+      break;
+  }
+}
+
+void GetFolderItemsResponseBuilder::PushMediaPlayerItem(
+    const std::shared_ptr<::bluetooth::Packet>& pkt,
+    const MediaPlayerItem& item) {
+  AddPayloadOctets1(pkt, 0x01);  // Media Player Item
+  uint16_t item_len = MediaPlayerItem::size(item) - 3;
+  AddPayloadOctets2(pkt, base::ByteSwap(item_len));  // Item length
+  AddPayloadOctets2(pkt, base::ByteSwap(item.id_));  // Player ID
+  AddPayloadOctets1(pkt, 0x01);                      // Player Type
+  AddPayloadOctets4(pkt, 0x00000000);                // Player Subtype
+  AddPayloadOctets1(
+      pkt, 0x02);  // Player Play Status // TODO: Add this as a passed field
+
+  // Features
+  AddPayloadOctets1(pkt, 0x00);
+  AddPayloadOctets1(pkt, 0x00);
+  AddPayloadOctets1(pkt, 0x00);
+  AddPayloadOctets1(pkt, 0x00);
+  AddPayloadOctets1(pkt, 0x00);
+  AddPayloadOctets1(pkt, 0xb7);
+  AddPayloadOctets1(pkt, 0x01);
+  if (item.browsable_) {
+    AddPayloadOctets1(pkt, 0x0C);
+    AddPayloadOctets1(pkt, 0x0a);
+  } else {
+    AddPayloadOctets1(pkt, 0x04);
+    AddPayloadOctets1(pkt, 0x00);
+  }
+  AddPayloadOctets1(pkt, 0x00);
+  AddPayloadOctets1(pkt, 0x00);
+  AddPayloadOctets1(pkt, 0x00);
+  AddPayloadOctets1(pkt, 0x00);
+  AddPayloadOctets1(pkt, 0x00);
+  AddPayloadOctets1(pkt, 0x00);
+  AddPayloadOctets1(pkt, 0x00);
+
+  AddPayloadOctets2(pkt, base::ByteSwap((uint16_t)0x006a));
+  uint16_t name_len = item.name_.size();
+  AddPayloadOctets2(pkt, base::ByteSwap(name_len));
+
+  for (const uint8_t& byte : item.name_) {
+    AddPayloadOctets1(pkt, byte);
+  }
+}
+
+void GetFolderItemsResponseBuilder::PushFolderItem(
+    const std::shared_ptr<::bluetooth::Packet>& pkt, const FolderItem& item) {
+  AddPayloadOctets1(pkt, 0x02);  // Folder Item
+  uint16_t item_len = FolderItem::size(item) - 3;
+  AddPayloadOctets2(pkt, base::ByteSwap(item_len));
+  AddPayloadOctets8(pkt, base::ByteSwap(item.uid_));
+  AddPayloadOctets1(pkt, item.folder_type_);
+  AddPayloadOctets1(pkt, item.is_playable_ ? 0x01 : 0x00);
+  AddPayloadOctets2(pkt,
+                    base::ByteSwap((uint16_t)0x006a));  // UTF-8 Character Set
+  uint16_t name_len = item.name_.size();
+  AddPayloadOctets2(pkt, base::ByteSwap(name_len));
+  for (const uint8_t& byte : item.name_) {
+    AddPayloadOctets1(pkt, byte);
+  }
+}
+
+void GetFolderItemsResponseBuilder::PushMediaElementItem(
+    const std::shared_ptr<::bluetooth::Packet>& pkt,
+    const MediaElementItem& item) {
+  AddPayloadOctets1(pkt, 0x03);  // Media Element Item
+  uint16_t item_len = MediaElementItem::size(item) - 3;
+  AddPayloadOctets2(pkt, base::ByteSwap(item_len));
+  AddPayloadOctets8(pkt, base::ByteSwap(item.uid_));
+  AddPayloadOctets1(pkt, 0x00);  // Media Type Audio
+  AddPayloadOctets2(pkt,
+                    base::ByteSwap((uint16_t)0x006a));  // UTF-8 Character Set
+  uint16_t name_len = item.name_.size();
+  AddPayloadOctets2(pkt, base::ByteSwap(name_len));
+  for (const uint8_t& byte : item.name_) {
+    AddPayloadOctets1(pkt, byte);
+  }
+
+  AddPayloadOctets1(pkt, (uint8_t)item.attributes_.size());
+  for (const auto& attribute : item.attributes_) {
+    AddPayloadOctets4(pkt, base::ByteSwap((uint32_t)attribute.first));
+    AddPayloadOctets2(pkt,
+                      base::ByteSwap((uint16_t)0x006a));  // UTF-8 Character Set
+
+    std::string attr_val = attribute.second;
+    uint16_t attr_len = attr_val.size();
+    ;
+    AddPayloadOctets2(pkt, base::ByteSwap(attr_len));
+    for (const uint8_t& byte : attr_val) {
+      AddPayloadOctets1(pkt, byte);
+    }
+  }
+}
+
+Scope GetFolderItemsRequest::GetScope() const {
+  auto it = begin() + BrowsePacket::kMinSize();
+  return static_cast<Scope>(*it);
+}
+
+uint32_t GetFolderItemsRequest::GetStartItem() const {
+  auto it = begin() + BrowsePacket::kMinSize() + static_cast<size_t>(1);
+  return base::ByteSwap(it.extract<uint32_t>());
+}
+
+uint32_t GetFolderItemsRequest::GetEndItem() const {
+  auto it = begin() + BrowsePacket::kMinSize() + static_cast<size_t>(5);
+  return base::ByteSwap(it.extract<uint32_t>());
+}
+
+uint8_t GetFolderItemsRequest::GetNumAttributes() const {
+  auto it = begin() + BrowsePacket::kMinSize() + static_cast<size_t>(9);
+  return *it;
+}
+
+std::vector<Attribute> GetFolderItemsRequest::GetAttributesRequested() const {
+  auto it = begin() + BrowsePacket::kMinSize() + static_cast<size_t>(9);
+
+  size_t number_of_attributes = it.extract<uint8_t>();
+  std::vector<Attribute> attribute_list;
+
+  // No attributes requested
+  if (number_of_attributes == 0xFF) return attribute_list;
+
+  // TODO: If the number of attributes equals 0, then all attributes are
+  // requested right now thats handled in the service itself, but it'd be nice
+  // to have this function return a vector with all the attributes
+
+  for (size_t i = 0; i < number_of_attributes; i++) {
+    attribute_list.push_back((Attribute)base::ByteSwap(it.extract<uint32_t>()));
+  }
+
+  return attribute_list;
+}
+
+bool GetFolderItemsRequest::IsValid() const {
+  if (!BrowsePacket::IsValid()) return false;
+  // The minimum size required to be valid
+  if (size() < kMinSize()) return false;
+
+  auto attr_count = GetNumAttributes();
+
+  // No items requested
+  if (attr_count == 0xFF) return true;
+
+  auto attr_start = begin() + kMinSize();
+
+  // Casting the int returned from end - attr_start should be fine. If an
+  // overflow occurs we can definitly say the packet is invalid
+  return (attr_count * sizeof(Attribute)) == (size_t)(end() - attr_start);
+}
+
+std::string GetFolderItemsRequest::ToString() const {
+  std::stringstream ss;
+  ss << "GetFolderItemsRequestPacket: " << std::endl;
+  ss << "  └ PDU = " << GetPdu() << std::endl;
+  ss << "  └ Length = " << GetLength() << std::endl;
+  ss << "  └ Scope = " << GetScope() << std::endl;
+  ss << "  └ Start Item = " << loghex(GetStartItem()) << std::endl;
+  ss << "  └ End Item = " << loghex(GetEndItem()) << std::endl;
+  ss << "  └ Attribute Count = " << loghex(GetNumAttributes()) << std::endl;
+
+  ss << std::endl;
+
+  return ss.str();
+}
+
+}  // namespace avrcp
+}  // namespace bluetooth
\ No newline at end of file
diff --git a/packet/avrcp/get_folder_items.h b/packet/avrcp/get_folder_items.h
new file mode 100644 (file)
index 0000000..1ab216a
--- /dev/null
@@ -0,0 +1,98 @@
+/*
+ * Copyright 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include "avrcp_browse_packet.h"
+
+namespace bluetooth {
+namespace avrcp {
+
+class GetFolderItemsResponseBuilder : public BrowsePacketBuilder {
+ public:
+  virtual ~GetFolderItemsResponseBuilder() = default;
+  static std::unique_ptr<GetFolderItemsResponseBuilder> MakePlayerListBuilder(
+      Status status, uint16_t uid_counter);
+  static std::unique_ptr<GetFolderItemsResponseBuilder> MakeVFSBuilder(
+      Status status, uint16_t uid_counter);
+  static std::unique_ptr<GetFolderItemsResponseBuilder> MakeNowPlayingBuilder(
+      Status status, uint16_t uid_counter);
+
+  virtual size_t size() const override;
+  virtual bool Serialize(
+      const std::shared_ptr<::bluetooth::Packet>& pkt) override;
+
+  void AddMediaPlayer(MediaPlayerItem item);
+  void AddSong(MediaElementItem item);
+  void AddFolder(FolderItem item);
+
+ protected:
+  Scope scope_;
+  std::vector<MediaListItem> items_;
+  Status status_;
+  uint16_t uid_counter_;
+
+  GetFolderItemsResponseBuilder(Scope scope, Status status,
+                                uint16_t uid_counter)
+      : BrowsePacketBuilder(BrowsePdu::GET_FOLDER_ITEMS),
+        scope_(scope),
+        status_(status),
+        uid_counter_(uid_counter){};
+
+ private:
+  void PushMediaListItem(const std::shared_ptr<::bluetooth::Packet>& pkt,
+                         const MediaListItem& item);
+  void PushMediaPlayerItem(const std::shared_ptr<::bluetooth::Packet>& pkt,
+                           const MediaPlayerItem& item);
+  void PushMediaElementItem(const std::shared_ptr<::bluetooth::Packet>& pkt,
+                            const MediaElementItem& item);
+  void PushFolderItem(const std::shared_ptr<::bluetooth::Packet>& pkt,
+                      const FolderItem& item);
+};
+
+class GetFolderItemsRequest : public BrowsePacket {
+ public:
+  virtual ~GetFolderItemsRequest() = default;
+
+  /**
+   * Avrcp Change Path Packet Layout
+   *   BrowsePacket:
+   *     uint8_t pdu_;
+   *     uint16_t length_;
+   *   GetFolderItemsRequest:
+   *     uint8_t scope_;
+   *     uint32_t start_item_;
+   *     uint32_t end_item_;
+   *     uint8_t attr_count_;
+   *     uint32_t[] attr_requested_;
+   */
+  static constexpr size_t kMinSize() { return BrowsePacket::kMinSize() + 10; }
+
+  Scope GetScope() const;
+  uint32_t GetStartItem() const;
+  uint32_t GetEndItem() const;
+  uint8_t GetNumAttributes() const;
+  std::vector<Attribute> GetAttributesRequested() const;
+
+  virtual bool IsValid() const override;
+  virtual std::string ToString() const override;
+
+ protected:
+  using BrowsePacket::BrowsePacket;
+};
+
+}  // namespace avrcp
+}  // namespace bluetooth
\ No newline at end of file
diff --git a/packet/avrcp/get_item_attributes.cc b/packet/avrcp/get_item_attributes.cc
new file mode 100644 (file)
index 0000000..e662437
--- /dev/null
@@ -0,0 +1,145 @@
+/*
+ * Copyright 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "get_item_attributes.h"
+
+namespace bluetooth {
+namespace avrcp {
+
+std::unique_ptr<GetItemAttributesResponseBuilder>
+GetItemAttributesResponseBuilder::MakeBuilder(Status status) {
+  std::unique_ptr<GetItemAttributesResponseBuilder> builder(
+      new GetItemAttributesResponseBuilder(status));
+
+  return builder;
+}
+
+GetItemAttributesResponseBuilder*
+GetItemAttributesResponseBuilder::AddAttributeEntry(AttributeEntry entry) {
+  CHECK(entries_.size() < 0xFF);
+  entries_.insert(entry);
+  return this;
+}
+
+GetItemAttributesResponseBuilder*
+GetItemAttributesResponseBuilder::AddAttributeEntry(Attribute attribute,
+                                                    std::string value) {
+  return AddAttributeEntry(AttributeEntry(attribute, value));
+}
+
+size_t GetItemAttributesResponseBuilder::size() const {
+  size_t len = BrowsePacket::kMinSize();
+  len += 1;  // Status
+  if (status_ != Status::NO_ERROR) return len;
+
+  len += 1;  // Number of attributes
+  for (const auto& attribute_entry : entries_) {
+    len += 4;  // Size of attr entry
+    len += 2;  // Size of value length field
+    len += 2;  // Size of character encoding
+    len += attribute_entry.second.length();
+  }
+  return len;
+}
+
+bool GetItemAttributesResponseBuilder::Serialize(
+    const std::shared_ptr<::bluetooth::Packet>& pkt) {
+  ReserveSpace(pkt, size());
+
+  BrowsePacketBuilder::PushHeader(pkt, size() - BrowsePacket::kMinSize());
+
+  AddPayloadOctets1(pkt, (uint8_t)status_);
+  if (status_ != Status::NO_ERROR) return true;
+
+  AddPayloadOctets1(pkt, entries_.size());
+  for (auto attribute_entry : entries_) {
+    AddPayloadOctets4(pkt, base::ByteSwap((uint32_t)attribute_entry.first));
+    uint16_t character_set = 0x006a;  // UTF-8
+    AddPayloadOctets2(pkt, base::ByteSwap(character_set));
+    uint16_t value_length = attribute_entry.second.length();
+    AddPayloadOctets2(pkt, base::ByteSwap(value_length));
+    for (const uint8_t& byte : attribute_entry.second) {
+      AddPayloadOctets1(pkt, byte);
+    }
+  }
+
+  return true;
+}
+
+Scope GetItemAttributesRequest::GetScope() const {
+  auto it = begin() + BrowsePacket::kMinSize();
+  return static_cast<Scope>(*it);
+}
+
+uint64_t GetItemAttributesRequest::GetUid() const {
+  auto it = begin() + BrowsePacket::kMinSize() + static_cast<size_t>(1);
+  return base::ByteSwap(it.extract<uint64_t>());
+}
+
+uint16_t GetItemAttributesRequest::GetUidCounter() const {
+  auto it = begin() + BrowsePacket::kMinSize() + static_cast<size_t>(9);
+  return base::ByteSwap(it.extract<uint16_t>());
+}
+
+uint8_t GetItemAttributesRequest::GetNumAttributes() const {
+  auto it = begin() + BrowsePacket::kMinSize() + static_cast<size_t>(11);
+  return *it;
+}
+
+std::vector<Attribute> GetItemAttributesRequest::GetAttributesRequested()
+    const {
+  auto it = begin() + BrowsePacket::kMinSize() + static_cast<size_t>(11);
+  size_t number_of_attributes = it.extract<uint8_t>();
+
+  std::vector<Attribute> attribute_list;
+  for (size_t i = 0; i < number_of_attributes; i++) {
+    attribute_list.push_back((Attribute)base::ByteSwap(it.extract<uint32_t>()));
+  }
+
+  return attribute_list;
+}
+
+bool GetItemAttributesRequest::IsValid() const {
+  if (!BrowsePacket::IsValid()) return false;
+  if (size() < kMinSize()) return false;
+
+  // Casting the int returned from end - attr_start should be fine. If an
+  // overflow occurs we can definitly say the packet is invalid
+  return (GetNumAttributes() * sizeof(Attribute)) == (size() - kMinSize());
+}
+
+std::string GetItemAttributesRequest::ToString() const {
+  std::stringstream ss;
+  ss << "GetItemAttributesRequestPacket: " << std::endl;
+  ss << "  └ PDU = " << GetPdu() << std::endl;
+  ss << "  └ Length = " << GetLength() << std::endl;
+  ss << "  └ Scope = " << GetScope() << std::endl;
+  ss << "  └ UID Requested = " << loghex(GetUid()) << std::endl;
+  ss << "  └ UID Counter = " << loghex(GetUidCounter()) << std::endl;
+  ss << "  └ Num Attributes = " << loghex(GetNumAttributes()) << std::endl;
+
+  auto attr_list = GetAttributesRequested();
+  ss << "  └ Attribute List: Size: " << attr_list.size() << std::endl;
+  for (auto it = attr_list.begin(); it != attr_list.end(); it++) {
+    ss << "      └ " << loghex((uint32_t)(*it)) << std::endl;
+  }
+  ss << std::endl;
+
+  return ss.str();
+}
+
+}  // namespace avrcp
+}  // namespace bluetooth
\ No newline at end of file
diff --git a/packet/avrcp/get_item_attributes.h b/packet/avrcp/get_item_attributes.h
new file mode 100644 (file)
index 0000000..efb50d1
--- /dev/null
@@ -0,0 +1,81 @@
+/*
+ * Copyright 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <map>
+
+#include "avrcp_browse_packet.h"
+
+namespace bluetooth {
+namespace avrcp {
+
+class GetItemAttributesResponseBuilder : public BrowsePacketBuilder {
+ public:
+  virtual ~GetItemAttributesResponseBuilder() = default;
+
+  static std::unique_ptr<GetItemAttributesResponseBuilder> MakeBuilder(
+      Status status);
+
+  GetItemAttributesResponseBuilder* AddAttributeEntry(AttributeEntry entry);
+  GetItemAttributesResponseBuilder* AddAttributeEntry(Attribute, std::string);
+
+  virtual size_t size() const override;
+  virtual bool Serialize(
+      const std::shared_ptr<::bluetooth::Packet>& pkt) override;
+
+ private:
+  Status status_;
+  std::map<Attribute, std::string> entries_;
+
+  GetItemAttributesResponseBuilder(Status status)
+      : BrowsePacketBuilder(BrowsePdu::GET_ITEM_ATTRIBUTES), status_(status) {}
+};
+
+class GetItemAttributesRequest : public BrowsePacket {
+ public:
+  virtual ~GetItemAttributesRequest() = default;
+
+  /**
+   * Avrcp Change Path Packet Layout
+   *   BrowsePacket:
+   *     uint8_t pdu_;
+   *     uint16_t length_;
+   *   GetItemAttributesRequest:
+   *     uint8_t scope_;
+   *     uint64_t uid_;
+   *     uint16_t uid_counter_;
+   *     uint8_t attr_count_;
+   *     uint32_t[] attr_requested_;
+   */
+  static constexpr size_t kMinSize() { return BrowsePacket::kMinSize() + 12; }
+
+  Scope GetScope() const;
+  uint64_t GetUid() const;
+  uint16_t GetUidCounter() const;
+  uint8_t GetNumAttributes()
+      const;  // If this value is zero, then all attributes are requested
+  std::vector<Attribute> GetAttributesRequested() const;
+
+  virtual bool IsValid() const override;
+  virtual std::string ToString() const override;
+
+ protected:
+  using BrowsePacket::BrowsePacket;
+};
+
+}  // namespace avrcp
+}  // namespace bluetooth
\ No newline at end of file
index 8993c50..8a40de9 100644 (file)
@@ -35,7 +35,7 @@ GetPlayStatusResponseBuilder::MakeBuilder(uint32_t song_length,
 }
 
 size_t GetPlayStatusResponseBuilder::size() const {
-  return VendorPacket::kHeaderSize() + 4 + 4 + 1;
+  return VendorPacket::kMinSize() + 4 + 4 + 1;
 }
 
 bool GetPlayStatusResponseBuilder::Serialize(
@@ -46,7 +46,7 @@ bool GetPlayStatusResponseBuilder::Serialize(
   PacketBuilder::PushHeader(pkt);
 
   // Push the avrcp vendor command headers
-  uint16_t parameter_count = size() - VendorPacket::kHeaderSize();
+  uint16_t parameter_count = size() - VendorPacket::kMinSize();
   VendorPacketBuilder::PushHeader(pkt, parameter_count);
 
   AddPayloadOctets4(pkt, base::ByteSwap(song_length_));
index f7fa0eb..5714c26 100644 (file)
@@ -41,6 +41,7 @@ class GetPlayStatusRequest : public VendorPacket {
    *     uint8_t packet_type;
    *     uint16_t param_length = 0;
    */
+  static constexpr size_t kMinSize() { return Packet::kMinSize() + 7; }
 
   // Overloaded Functions
   virtual bool IsValid() const override;
diff --git a/packet/avrcp/get_total_number_of_items.cc b/packet/avrcp/get_total_number_of_items.cc
new file mode 100644 (file)
index 0000000..ab601ea
--- /dev/null
@@ -0,0 +1,79 @@
+/*
+ * Copyright 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "get_total_number_of_items.h"
+
+namespace bluetooth {
+namespace avrcp {
+
+std::unique_ptr<GetTotalNumberOfItemsResponseBuilder>
+GetTotalNumberOfItemsResponseBuilder::MakeBuilder(
+    Status status, uint16_t uid_counter, uint32_t num_items_in_folder) {
+  std::unique_ptr<GetTotalNumberOfItemsResponseBuilder> builder(
+      new GetTotalNumberOfItemsResponseBuilder(status, uid_counter,
+                                               num_items_in_folder));
+
+  return builder;
+}
+
+size_t GetTotalNumberOfItemsResponseBuilder::size() const {
+  size_t len = BrowsePacket::kMinSize();
+  len += 1;  // Status
+
+  if (status_ != Status::NO_ERROR) return len;
+
+  len += 2;  // UID Counter
+  len += 4;  // Number of items in folder
+  return len;
+}
+
+bool GetTotalNumberOfItemsResponseBuilder::Serialize(
+    const std::shared_ptr<::bluetooth::Packet>& pkt) {
+  ReserveSpace(pkt, size());
+
+  BrowsePacketBuilder::PushHeader(pkt, size() - BrowsePacket::kMinSize());
+
+  AddPayloadOctets1(pkt, (uint8_t)status_);
+
+  if (status_ != Status::NO_ERROR) return true;
+  AddPayloadOctets2(pkt, base::ByteSwap(uid_counter_));
+  AddPayloadOctets4(pkt, base::ByteSwap(num_items_in_folder_));
+  return true;
+}
+
+Scope GetTotalNumberOfItemsRequest::GetScope() const {
+  auto it = begin() + BrowsePacket::kMinSize();
+  return static_cast<Scope>(*it);
+}
+
+bool GetTotalNumberOfItemsRequest::IsValid() const {
+  if (!BrowsePacket::IsValid()) return false;
+  return size() == kMinSize();
+}
+
+std::string GetTotalNumberOfItemsRequest::ToString() const {
+  std::stringstream ss;
+  ss << "GetTotalNumberOfItemsRequest: " << std::endl;
+  ss << "  └ PDU = " << GetPdu() << std::endl;
+  ss << "  └ Length = " << GetLength() << std::endl;
+  ss << "  └ Scope = " << GetScope() << std::endl;
+  ss << std::endl;
+
+  return ss.str();
+}
+
+}  // namespace avrcp
+}  // namespace bluetooth
diff --git a/packet/avrcp/get_total_number_of_items.h b/packet/avrcp/get_total_number_of_items.h
new file mode 100644 (file)
index 0000000..51842c9
--- /dev/null
@@ -0,0 +1,72 @@
+/*
+ * Copyright 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include "avrcp_browse_packet.h"
+
+namespace bluetooth {
+namespace avrcp {
+
+class GetTotalNumberOfItemsResponseBuilder : public BrowsePacketBuilder {
+ public:
+  virtual ~GetTotalNumberOfItemsResponseBuilder() = default;
+
+  static std::unique_ptr<GetTotalNumberOfItemsResponseBuilder> MakeBuilder(
+      Status status, uint16_t uid_counter, uint32_t num_items_in_folder);
+
+  virtual size_t size() const override;
+  virtual bool Serialize(
+      const std::shared_ptr<::bluetooth::Packet>& pkt) override;
+
+ protected:
+  Status status_;
+  uint16_t uid_counter_;
+  uint32_t num_items_in_folder_;
+
+  GetTotalNumberOfItemsResponseBuilder(Status status, uint16_t uid_counter,
+                                       uint32_t num_items_in_folder)
+      : BrowsePacketBuilder(BrowsePdu::GET_TOTAL_NUMBER_OF_ITEMS),
+        status_(status),
+        uid_counter_(uid_counter),
+        num_items_in_folder_(num_items_in_folder){};
+};
+
+class GetTotalNumberOfItemsRequest : public BrowsePacket {
+ public:
+  virtual ~GetTotalNumberOfItemsRequest() = default;
+
+  /**
+   * AVRCP Get Total Number Of Items Packet Layout
+   *   BrowsePacket:
+   *     uint8_t pdu_;
+   *     uint16_t length_;
+   *   GetTotalNumberOfItemsRequest:
+   *     uint8_t scope_;
+   */
+  static constexpr size_t kMinSize() { return BrowsePacket::kMinSize() + 1; }
+
+  Scope GetScope() const;
+
+  virtual bool IsValid() const override;
+  virtual std::string ToString() const override;
+
+ protected:
+  using BrowsePacket::BrowsePacket;
+};
+
+}  // namespace avrcp
+}  // namespace bluetooth
\ No newline at end of file
index 3777211..a384cc0 100644 (file)
@@ -28,7 +28,7 @@ std::unique_ptr<PassThroughPacketBuilder> PassThroughPacketBuilder::MakeBuilder(
 }
 
 size_t PassThroughPacketBuilder::size() const {
-  return PassThroughPacket::kHeaderSize();
+  return PassThroughPacket::kMinSize();
 }
 
 bool PassThroughPacketBuilder::Serialize(
@@ -47,14 +47,14 @@ bool PassThroughPacketBuilder::Serialize(
 }
 
 bool PassThroughPacket::GetPushed() const {
-  return (*(begin() + Packet::kHeaderSize()) & 0b10000000) == 0;
+  return (*(begin() + Packet::kMinSize()) & 0b10000000) == 0;
 }
 
 uint8_t PassThroughPacket::GetOperationId() const {
-  return *(begin() + Packet::kHeaderSize()) & 0b01111111;
+  return *(begin() + Packet::kMinSize()) & 0b01111111;
 }
 
-bool PassThroughPacket::IsValid() const { return (size() == kHeaderSize()); }
+bool PassThroughPacket::IsValid() const { return size() == kMinSize(); }
 
 std::string PassThroughPacket::ToString() const {
   std::stringstream ss;
index 92f6c1f..f2cf1d7 100644 (file)
@@ -59,7 +59,7 @@ class PassThroughPacket : public Packet {
    *     uint8_t opperation_id : 7;
    *     uint8_t data_length;
    */
-  static constexpr size_t kHeaderSize() { return Packet::kHeaderSize() + 2; }
+  static constexpr size_t kMinSize() { return Packet::kMinSize() + 2; }
 
   // Getter Functions
   bool GetPushed() const;
diff --git a/packet/avrcp/play_item.cc b/packet/avrcp/play_item.cc
new file mode 100644 (file)
index 0000000..27b242b
--- /dev/null
@@ -0,0 +1,89 @@
+/*
+ * Copyright 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "play_item.h"
+
+namespace bluetooth {
+namespace avrcp {
+
+std::unique_ptr<PlayItemResponseBuilder> PlayItemResponseBuilder::MakeBuilder(
+    Status status) {
+  std::unique_ptr<PlayItemResponseBuilder> builder(
+      new PlayItemResponseBuilder(status));
+
+  return builder;
+}
+
+size_t PlayItemResponseBuilder::size() const {
+  size_t len = VendorPacket::kMinSize();
+  len += 1;  // Status
+  return len;
+}
+
+bool PlayItemResponseBuilder::Serialize(
+    const std::shared_ptr<::bluetooth::Packet>& pkt) {
+  ReserveSpace(pkt, size());
+
+  PacketBuilder::PushHeader(pkt);
+
+  VendorPacketBuilder::PushHeader(pkt, size() - VendorPacket::kMinSize());
+
+  AddPayloadOctets1(pkt, (uint8_t)status_);
+
+  return true;
+}
+
+Scope PlayItemRequest::GetScope() const {
+  auto it = begin() + VendorPacket::kMinSize();
+  return static_cast<Scope>(*it);
+}
+
+uint64_t PlayItemRequest::GetUid() const {
+  auto it = begin() + VendorPacket::kMinSize() + static_cast<size_t>(1);
+  return base::ByteSwap(it.extract<uint64_t>());
+}
+
+uint16_t PlayItemRequest::GetUidCounter() const {
+  auto it = begin() + VendorPacket::kMinSize() + static_cast<size_t>(9);
+  return base::ByteSwap(it.extract<uint16_t>());
+}
+
+bool PlayItemRequest::IsValid() const {
+  if (!VendorPacket::IsValid()) return false;
+  return size() == kMinSize();
+}
+
+std::string PlayItemRequest::ToString() const {
+  std::stringstream ss;
+  ss << "PlayItemRequest: " << std::endl;
+  ss << "  └ cType = " << GetCType() << std::endl;
+  ss << "  └ Subunit Type = " << loghex(GetSubunitType()) << std::endl;
+  ss << "  └ Subunit ID = " << loghex(GetSubunitId()) << std::endl;
+  ss << "  └ OpCode = " << GetOpcode() << std::endl;
+  ss << "  └ Company ID = " << loghex(GetCompanyId()) << std::endl;
+  ss << "  └ Command PDU = " << GetCommandPdu() << std::endl;
+  ss << "  └ PacketType = " << GetPacketType() << std::endl;
+  ss << "  └ Parameter Length = " << loghex(GetParameterLength()) << std::endl;
+  ss << "  └ Scope = " << GetScope() << std::endl;
+  ss << "  └ UID = " << loghex(GetUid()) << std::endl;
+  ss << "  └ UID Counter = " << loghex(GetUidCounter()) << std::endl;
+  ss << std::endl;
+
+  return ss.str();
+}
+
+}  // namespace avrcp
+}  // namespace bluetooth
\ No newline at end of file
diff --git a/packet/avrcp/play_item.h b/packet/avrcp/play_item.h
new file mode 100644 (file)
index 0000000..e1c2d48
--- /dev/null
@@ -0,0 +1,78 @@
+/*
+ * Copyright 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include "vendor_packet.h"
+
+namespace bluetooth {
+namespace avrcp {
+
+class PlayItemResponseBuilder : public VendorPacketBuilder {
+ public:
+  virtual ~PlayItemResponseBuilder() = default;
+
+  static std::unique_ptr<PlayItemResponseBuilder> MakeBuilder(Status status);
+
+  virtual size_t size() const override;
+  virtual bool Serialize(
+      const std::shared_ptr<::bluetooth::Packet>& pkt) override;
+
+ protected:
+  Status status_;
+
+  PlayItemResponseBuilder(Status status)
+      : VendorPacketBuilder(CType::ACCEPTED, CommandPdu::PLAY_ITEM,
+                            PacketType::SINGLE),
+        status_(status){};
+};
+
+class PlayItemRequest : public VendorPacket {
+ public:
+  virtual ~PlayItemRequest() = default;
+
+  /**
+   * AVRCP Play Item Request Packet Layout
+   *   AvrcpPacket:
+   *     CType c_type_;
+   *     uint8_t subunit_type_ : 5;
+   *     uint8_t subunit_id_ : 3;
+   *     Opcode opcode_;
+   *   VendorPacket:
+   *     uint8_t company_id[3];
+   *     uint8_t command_pdu;
+   *     uint8_t packet_type;
+   *     uint16_t parameter_length;
+   *   PlayItemRequest:
+   *     uint8_t scope_;
+   *     uint64_t uid_;
+   *     uint16_t uid_counter_;
+   */
+  static constexpr size_t kMinSize() { return VendorPacket::kMinSize() + 11; }
+
+  Scope GetScope() const;
+  uint64_t GetUid() const;
+  uint16_t GetUidCounter() const;
+
+  virtual bool IsValid() const override;
+  virtual std::string ToString() const override;
+
+ protected:
+  using VendorPacket::VendorPacket;
+};
+
+}  // namespace avrcp
+}  // namespace bluetooth
\ No newline at end of file
index 00da8dc..1bf2bf0 100644 (file)
@@ -104,7 +104,7 @@ size_t RegisterNotificationResponseBuilder::size() const {
   else if (event_ == Event::PLAYBACK_POS_CHANGED)
     data_size = 4;
 
-  return VendorPacket::kHeaderSize() + 1 + data_size;
+  return VendorPacket::kMinSize() + 1 + data_size;
 }
 
 bool RegisterNotificationResponseBuilder::Serialize(
@@ -146,17 +146,17 @@ bool RegisterNotificationResponseBuilder::Serialize(
 }
 
 Event RegisterNotificationRequest::GetEventRegistered() const {
-  auto value = *(begin() + VendorPacket::kHeaderSize());
+  auto value = *(begin() + VendorPacket::kMinSize());
   return static_cast<Event>(value);
 }
 
 uint32_t RegisterNotificationRequest::GetInterval() const {
-  auto it = begin() + VendorPacket::kHeaderSize() + static_cast<size_t>(1);
+  auto it = begin() + VendorPacket::kMinSize() + static_cast<size_t>(1);
   return base::ByteSwap(it.extract<uint32_t>());
 }
 
 bool RegisterNotificationRequest::IsValid() const {
-  return (size() == kHeaderSize());
+  return (size() == kMinSize());
 }
 
 std::string RegisterNotificationRequest::ToString() const {
index cff6121..a22f177 100644 (file)
@@ -83,9 +83,7 @@ class RegisterNotificationRequest : public VendorPacket {
    *     uint8_t event_id;
    *     uint32_t interval;  // Only used for PLAYBACK_POS_CHANGED
    */
-  static constexpr size_t kHeaderSize() {
-    return VendorPacket::kHeaderSize() + 5;
-  }
+  static constexpr size_t kMinSize() { return VendorPacket::kMinSize() + 5; }
 
   // Getter Functions
   Event GetEventRegistered() const;
diff --git a/packet/avrcp/set_browsed_player.cc b/packet/avrcp/set_browsed_player.cc
new file mode 100644 (file)
index 0000000..b8463fa
--- /dev/null
@@ -0,0 +1,103 @@
+/*
+ * Copyright 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "set_browsed_player.h"
+
+namespace bluetooth {
+namespace avrcp {
+
+std::unique_ptr<SetBrowsedPlayerResponseBuilder>
+SetBrowsedPlayerResponseBuilder::MakeBuilder(Status status,
+                                             uint16_t uid_counter,
+                                             uint32_t num_items_in_folder,
+                                             uint8_t folder_depth,
+                                             std::string folder_name) {
+  std::unique_ptr<SetBrowsedPlayerResponseBuilder> builder(
+      new SetBrowsedPlayerResponseBuilder(
+          status, uid_counter, num_items_in_folder, folder_depth, folder_name));
+
+  return builder;
+}
+
+size_t SetBrowsedPlayerResponseBuilder::size() const {
+  size_t len = BrowsePacket::kMinSize();
+  len += 1;  // Status
+
+  // If the status isn't success the rest of the fields are ommited
+  if (status_ != Status::NO_ERROR) return len;
+
+  len += 2;  // UID Counter
+  len += 4;  // Number of items in folder
+  len += 2;  // UTF-8 Character Set
+  len += 1;  // Folder Depth
+
+  // This is only included if the folder returned isn't the root folder
+  if (folder_depth_ != 0) {
+    len += 2;                    // Folder Name Size;
+    len += folder_name_.size();  // Folder Name
+  }
+
+  return len;
+}
+
+bool SetBrowsedPlayerResponseBuilder::Serialize(
+    const std::shared_ptr<::bluetooth::Packet>& pkt) {
+  ReserveSpace(pkt, size());
+
+  BrowsePacketBuilder::PushHeader(pkt, size() - BrowsePacket::kMinSize());
+
+  AddPayloadOctets1(pkt, (uint8_t)status_);
+
+  if (status_ != Status::NO_ERROR) return true;
+  AddPayloadOctets2(pkt, base::ByteSwap(uid_counter_));
+  AddPayloadOctets4(pkt, base::ByteSwap(num_items_in_folder_));
+  AddPayloadOctets2(pkt, base::ByteSwap((uint16_t)0x006a));  // UTF-8
+  AddPayloadOctets1(pkt, folder_depth_);
+
+  // Skip adding the folder name if the folder depth is 0
+  if (folder_depth_ == 0) return true;
+  uint16_t folder_name_len = folder_name_.size();
+  AddPayloadOctets2(pkt, base::ByteSwap(folder_name_len));
+  for (auto it = folder_name_.begin(); it != folder_name_.end(); it++) {
+    AddPayloadOctets1(pkt, *it);
+  }
+
+  return true;
+}
+
+uint16_t SetBrowsedPlayerRequest::GetPlayerId() const {
+  auto it = begin() + BrowsePacket::kMinSize();
+  return base::ByteSwap(it.extract<uint16_t>());
+}
+
+bool SetBrowsedPlayerRequest::IsValid() const {
+  if (!BrowsePacket::IsValid()) return false;
+  return size() == kMinSize();
+}
+
+std::string SetBrowsedPlayerRequest::ToString() const {
+  std::stringstream ss;
+  ss << "SetBrowsedPlayerRequestPacket: " << std::endl;
+  ss << "  └ PDU = " << GetPdu() << std::endl;
+  ss << "  └ Length = " << GetLength() << std::endl;
+  ss << "  └ Player ID = " << loghex(GetPlayerId()) << std::endl;
+  ss << std::endl;
+
+  return ss.str();
+}
+
+}  // namespace avrcp
+}  // namespace bluetooth
\ No newline at end of file
diff --git a/packet/avrcp/set_browsed_player.h b/packet/avrcp/set_browsed_player.h
new file mode 100644 (file)
index 0000000..336c4e1
--- /dev/null
@@ -0,0 +1,78 @@
+/*
+ * Copyright 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include "avrcp_browse_packet.h"
+
+namespace bluetooth {
+namespace avrcp {
+
+class SetBrowsedPlayerResponseBuilder : public BrowsePacketBuilder {
+ public:
+  virtual ~SetBrowsedPlayerResponseBuilder() = default;
+
+  static std::unique_ptr<SetBrowsedPlayerResponseBuilder> MakeBuilder(
+      Status status, uint16_t uid_counter, uint32_t num_items_in_folder,
+      uint8_t folder_depth, std::string folder_name);
+
+  virtual size_t size() const override;
+  virtual bool Serialize(
+      const std::shared_ptr<::bluetooth::Packet>& pkt) override;
+
+ protected:
+  Status status_;
+  uint16_t uid_counter_;
+  uint32_t num_items_in_folder_;
+  uint8_t folder_depth_;
+  std::string folder_name_;
+
+  SetBrowsedPlayerResponseBuilder(Status status, uint16_t uid_counter,
+                                  uint32_t num_items_in_folder,
+                                  uint8_t folder_depth, std::string folder_name)
+      : BrowsePacketBuilder(BrowsePdu::SET_BROWSED_PLAYER),
+        status_(status),
+        uid_counter_(uid_counter),
+        num_items_in_folder_(num_items_in_folder),
+        folder_depth_(folder_depth),
+        folder_name_(folder_name) {}
+};
+
+class SetBrowsedPlayerRequest : public BrowsePacket {
+ public:
+  virtual ~SetBrowsedPlayerRequest() = default;
+
+  /**
+   * Avrcp Change Path Packet Layout
+   *   BrowsePacket:
+   *     uint8_t pdu_;
+   *     uint16_t length_;
+   *   GetFolderItemsRequest:
+   *     uint16_t player_id_;
+   */
+  static constexpr size_t kMinSize() { return BrowsePacket::kMinSize() + 2; }
+
+  uint16_t GetPlayerId() const;
+
+  virtual bool IsValid() const override;
+  virtual std::string ToString() const override;
+
+ protected:
+  using BrowsePacket::BrowsePacket;
+};
+
+}  // namespace avrcp
+}  // namespace bluetooth
\ No newline at end of file
index 96db232..ceb2eb0 100644 (file)
@@ -35,7 +35,7 @@ std::unique_ptr<VendorPacketBuilder> VendorPacketBuilder::MakeBuilder(
 }
 
 size_t VendorPacketBuilder::size() const {
-  return VendorPacket::kHeaderSize() + payload_->size();
+  return VendorPacket::kMinSize() + payload_->size();
 }
 
 bool VendorPacketBuilder::Serialize(
@@ -79,29 +79,29 @@ bool VendorPacketBuilder::PushAttributeValue(
 }
 
 uint32_t VendorPacket::GetCompanyId() const {
-  return PullCompanyId(begin() + Packet::kHeaderSize());
+  return PullCompanyId(begin() + Packet::kMinSize());
 }
 
 CommandPdu VendorPacket::GetCommandPdu() const {
-  auto value = *(begin() + Packet::kHeaderSize() + static_cast<size_t>(3));
+  auto value = *(begin() + Packet::kMinSize() + static_cast<size_t>(3));
   return static_cast<CommandPdu>(value);
 }
 
 PacketType VendorPacket::GetPacketType() const {
-  auto value = *(begin() + Packet::kHeaderSize() + static_cast<size_t>(4));
+  auto value = *(begin() + Packet::kMinSize() + static_cast<size_t>(4));
   return static_cast<PacketType>(value);
 }
 
 uint16_t VendorPacket::GetParameterLength() const {
-  auto it = begin() + Packet::kHeaderSize() + static_cast<size_t>(5);
+  auto it = begin() + Packet::kMinSize() + static_cast<size_t>(5);
   // Swap to little endian
   return base::ByteSwap(it.extract<uint16_t>());
 }
 
 bool VendorPacket::IsValid() const {
-  if (size() < VendorPacket::kHeaderSize()) return false;
+  if (size() < VendorPacket::kMinSize()) return false;
 
-  auto start = begin() + VendorPacket::kHeaderSize();
+  auto start = begin() + VendorPacket::kMinSize();
   // Even if end is less than start and a sign extension occurs, thats fine as
   // its pretty definitive proof that the packet is poorly formated
   return GetParameterLength() == (end() - start);
index ac3305f..b9e1f10 100644 (file)
@@ -23,6 +23,8 @@ namespace avrcp {
 
 class VendorPacketBuilder : public avrcp::PacketBuilder {
  public:
+  virtual ~VendorPacketBuilder() = default;
+
   static std::unique_ptr<VendorPacketBuilder> MakeBuilder(
       CType ctype, CommandPdu pdu, PacketType packet_type,
       std::unique_ptr<::bluetooth::PacketBuilder> payload);
@@ -67,7 +69,7 @@ class VendorPacket : public avrcp::Packet {
    *     uint16_t parameter_length;
    *   uint8_t[] payload;
    */
-  static constexpr size_t kHeaderSize() { return Packet::kHeaderSize() + 7; };
+  static constexpr size_t kMinSize() { return Packet::kMinSize() + 7; };
 
   // Getter Functions
   uint32_t GetCompanyId() const;
index f2edd70..9aa37a4 100644 (file)
 #include "avrcp/get_play_status_packet.h"
 #include "avrcp/pass_through_packet.h"
 #include "avrcp/register_notification_packet.h"
-#include "avrcp/vendor_packet.h"
\ No newline at end of file
+#include "avrcp/vendor_packet.h"
+
+#include "avrcp/avrcp_browse_packet.h"
+#include "avrcp/change_path.h"
+#include "avrcp/get_folder_items.h"
+#include "avrcp/get_item_attributes.h"
+#include "avrcp/get_total_number_of_items.h"
+#include "avrcp/play_item.h"
+#include "avrcp/set_browsed_player.h"
\ No newline at end of file
diff --git a/packet/tests/avrcp/avrcp_browse_packet_test.cc b/packet/tests/avrcp/avrcp_browse_packet_test.cc
new file mode 100644 (file)
index 0000000..cde0867
--- /dev/null
@@ -0,0 +1,119 @@
+/*
+ * Copyright 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <gtest/gtest.h>
+
+#include "avrcp_browse_packet.h"
+#include "avrcp_test_packets.h"
+#include "packet_test_helper.h"
+
+namespace bluetooth {
+
+// A helper class that has public accessors to protected methods
+class TestPacketBuilder : public PacketBuilder {
+ public:
+  static std::unique_ptr<TestPacketBuilder> MakeBuilder(
+      std::vector<uint8_t> data) {
+    std::unique_ptr<TestPacketBuilder> builder(new TestPacketBuilder(data));
+    return builder;
+  };
+
+  // Make all the utility functions public
+  using PacketBuilder::ReserveSpace;
+  using PacketBuilder::AddPayloadOctets1;
+  using PacketBuilder::AddPayloadOctets2;
+  using PacketBuilder::AddPayloadOctets3;
+  using PacketBuilder::AddPayloadOctets4;
+  using PacketBuilder::AddPayloadOctets6;
+  using PacketBuilder::AddPayloadOctets8;
+
+  size_t size() const override { return data_.size(); };
+
+  bool Serialize(const std::shared_ptr<Packet>& pkt) override {
+    ReserveSpace(pkt, size());
+
+    for (uint8_t byte : data_) {
+      AddPayloadOctets1(pkt, byte);
+    }
+
+    return true;
+  }
+
+  TestPacketBuilder(std::vector<uint8_t> data) : data_(data){};
+
+  std::vector<uint8_t> data_;
+};
+
+namespace avrcp {
+
+using TestBrowsePacket = TestPacketType<BrowsePacket>;
+
+TEST(AvrcpBrowsePacketBuilderTest, buildPacketTest) {
+  std::vector<uint8_t> get_folder_items_request_payload = {
+      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00};
+  auto payload_builder =
+      TestPacketBuilder::MakeBuilder(get_folder_items_request_payload);
+
+  auto builder = BrowsePacketBuilder::MakeBuilder(BrowsePdu::GET_FOLDER_ITEMS,
+                                                  std::move(payload_builder));
+
+  ASSERT_EQ(builder->size(), get_folder_items_request.size());
+
+  auto test_packet = TestBrowsePacket::Make();
+  builder->Serialize(test_packet);
+  ASSERT_EQ(test_packet->GetData(), get_folder_items_request);
+}
+
+TEST(AvrcpBrowsePacketTest, gettersTest) {
+  auto test_browse_packet = TestBrowsePacket::Make(get_folder_items_request);
+
+  ASSERT_EQ(test_browse_packet->GetPdu(), BrowsePdu::GET_FOLDER_ITEMS);
+  ASSERT_EQ(test_browse_packet->GetLength(), 10u);
+}
+
+TEST(AvrcpBrowsePacketTest, payloadBoundsTest) {
+  auto test_browse_packet = TestBrowsePacket::Make(get_folder_items_request);
+  std::vector<uint8_t> get_folder_items_request_payload = {
+      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00};
+
+  // Make a folder items payload packet out of the payload of the browse packet
+  auto get_folder_items_payload = TestBrowsePacket::Make(test_browse_packet);
+
+  for (size_t i = 0; i < get_folder_items_request_payload.size(); i++) {
+    ASSERT_EQ((*get_folder_items_payload)[i],
+              get_folder_items_request_payload[i]);
+  }
+}
+
+TEST(AvrcpBrowsePacketTest, validTest) {
+  auto test_browse_packet = TestBrowsePacket::Make(get_folder_items_request);
+
+  ASSERT_TRUE(test_browse_packet->IsValid());
+}
+
+TEST(AvrcpBrowsePacketTest, invalidTest) {
+  auto packet_copy = get_folder_items_request;
+  packet_copy.push_back(0x00);
+  auto test_browse_packet = TestBrowsePacket::Make(packet_copy);
+  ASSERT_FALSE(test_browse_packet->IsValid());
+
+  std::vector<uint8_t> short_packet = {0x00, 0x01};
+  test_browse_packet = TestBrowsePacket::Make(short_packet);
+  ASSERT_FALSE(test_browse_packet->IsValid());
+}
+
+}  // namespace avrcp
+}  // namespace bluetooth
\ No newline at end of file
index 7d1d5be..8a438b3 100644 (file)
@@ -14,9 +14,6 @@
  * limitations under the License.
  */
 
-#include <base/logging.h>
-
-#include <gmock/gmock.h>
 #include <gtest/gtest.h>
 
 #include "avrcp_packet.h"
@@ -106,6 +103,7 @@ TEST(AvrcpPacketTest, payloadBoundsTest) {
 
   std::vector<uint8_t> get_cap_payload_data = {0x00, 0x19, 0x58, 0x10,
                                                0x00, 0x00, 0x01, 0x03};
+
   auto get_cap_payload_packet = TestAvrcpPacket::Make(test_avrcp_packet);
 
   // We are unable to do a direct vector compare here as one of the packets is
index 8b11d5b..ebaa9a6 100644 (file)
@@ -14,8 +14,6 @@
  * limitations under the License.
  */
 
-#include <base/logging.h>
-
 #include <gtest/gtest.h>
 
 #include "avrcp_reject_packet.h"
index 2641ae0..2a822c1 100644 (file)
 // AVRCP packets pulled from wireshark
 namespace {
 
-// An ACL packet containing an AVRCP Get Capabilities Request
-std::vector<uint8_t> get_capabilities_request_acl_packet = {
-    0x04, 0x20, 0x12, 0x00, 0x0e, 0x00, 0x4c, 0x00, 0x10, 0x11, 0x0e,
-    0x01, 0x48, 0x00, 0x00, 0x19, 0x58, 0x10, 0x00, 0x00, 0x01, 0x03};
-
-// Offset into the ACL packet where the Get Capabilities Request data starts
-size_t get_capabilities_request_data_offset = 11;
-
 // AVRCP Get Capabilities Request packet
 std::vector<uint8_t> get_capabilities_request = {
     0x01, 0x48, 0x00, 0x00, 0x19, 0x58, 0x10, 0x00, 0x00, 0x01, 0x03};
@@ -118,4 +110,124 @@ std::vector<uint8_t> changed_play_pos_notification = {
 std::vector<uint8_t> reject_player_app_settings_response = {
     0x0a, 0x48, 0x00, 0x00, 0x19, 0x58, 0x11, 0x00, 0x00, 0x01, 0x00};
 
+// AVRCP Browse Get Folder Items Request packet for media players with
+// the following data:
+//    scope = 0x00 (Media Player List)
+//    start_item = 0x00
+//    end_item = 0x03
+//    attributes_requested: none
+std::vector<uint8_t> get_folder_items_request = {0x71, 0x00, 0x0a, 0x00, 0x00,
+                                                 0x00, 0x00, 0x00, 0x00, 0x00,
+                                                 0x00, 0x03, 0x00};
+
+// AVRCP Browse Get Folder Items Request packet for vfs with
+// the following data:
+//    scope = 0x01 (VFS)
+//    start_item = 0x00
+//    end_item = 0x05
+//    attributes_requested: TITLE
+std::vector<uint8_t> get_folder_items_request_vfs = {
+    0x71, 0x00, 0x0e, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x05, 0x01, 0x00, 0x00, 0x00, 0x01};
+
+// AVRCP Browse Get Folder Items Response packet with range out of bounds error
+std::vector<uint8_t> get_folder_items_error_response = {0x71, 0x00, 0x01, 0x0b};
+
+// AVRCP Browse Get Folder Items Response packet for media players
+// Contains one media player with the following fields:
+//    id = 0x0001
+//    name = "com.google.android.music"
+//    browsing_supported = true
+std::vector<uint8_t> get_folder_items_media_player_response = {
+    0x71, 0x00, 0x3c, 0x04, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0x34,
+    0x00, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0xb7, 0x01, 0x0c, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x6a, 0x00, 0x18, 0x63, 0x6f, 0x6d, 0x2e, 0x67,
+    0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x61, 0x6e, 0x64, 0x72, 0x6f,
+    0x69, 0x64, 0x2e, 0x6d, 0x75, 0x73, 0x69, 0x63};
+
+// AVRCP Browse Get Folder Items Response packet with one folder
+// with the following fields:
+//    uid = 0x0000000000000001
+//    type = 0x00 (Mixed);
+//    name = "Test Folder"
+//    is_playable = true
+std::vector<uint8_t> get_folder_items_folder_response = {
+    0x71, 0x00, 0x21, 0x04, 0x00, 0x00, 0x00, 0x01, 0x02, 0x00, 0x19, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x6a, 0x00,
+    0x0b, 0x54, 0x65, 0x73, 0x74, 0x20, 0x46, 0x6f, 0x6c, 0x64, 0x65, 0x72};
+
+// AVRCP Browse Get Folder Items Response packet with one song
+// with the following fields:
+//    uid = 0x0000000000000002
+//    name = "Test Title"
+//    attribute[TITLE] = "Test Title"
+std::vector<uint8_t> get_folder_items_song_response = {
+    0x71, 0x00, 0x32, 0x04, 0x00, 0x00, 0x00, 0x01, 0x03, 0x00, 0x2a,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x6a,
+    0x00, 0x0a, 0x54, 0x65, 0x73, 0x74, 0x20, 0x54, 0x69, 0x74, 0x6c,
+    0x65, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x6a, 0x00, 0x0a, 0x54,
+    0x65, 0x73, 0x74, 0x20, 0x54, 0x69, 0x74, 0x6c, 0x65};
+
+// AVRCP Browse Change Path Request down to folder with UID 0x0000000000000002
+std::vector<uint8_t> change_path_request = {0x72, 0x00, 0x0b, 0x00, 0x00,
+                                            0x01, 0x00, 0x00, 0x00, 0x00,
+                                            0x00, 0x00, 0x00, 0x02};
+
+// AVRCP Browse Change Path Response with two items in current folder
+std::vector<uint8_t> change_path_response = {0x72, 0x00, 0x05, 0x04,
+                                             0x00, 0x00, 0x00, 0x02};
+
+// AVRCP Browse Change Path Response with an error of invalid direction
+std::vector<uint8_t> change_path_error_response = {0x72, 0x00, 0x01, 0x07};
+
+// AVRCP Get Item Attributes request with all attributes requested
+// with the following fields:
+//    scope = 0x03 (Now Playing List)
+//    uid_counter = 0x0000
+//    uid = 0x0000000000000001
+std::vector<uint8_t> get_item_attributes_request_all_attributes = {
+    0x73, 0x00, 0x28, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x01, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+    0x02, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00,
+    0x00, 0x05, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x07};
+
+// AVRCP Get Item Attributes Response with the following attributes:
+//    title = "Test Song"
+//    artist = "Test Artist"
+//    album = "Test Album"
+std::vector<uint8_t> get_item_attributes_song_response = {
+    0x73, 0x00, 0x38, 0x04, 0x03, 0x00, 0x00, 0x00, 0x01, 0x00, 0x6a, 0x00,
+    0x09, 0x54, 0x65, 0x73, 0x74, 0x20, 0x53, 0x6f, 0x6e, 0x67, 0x00, 0x00,
+    0x00, 0x02, 0x00, 0x6a, 0x00, 0x0b, 0x54, 0x65, 0x73, 0x74, 0x20, 0x41,
+    0x72, 0x74, 0x69, 0x73, 0x74, 0x00, 0x00, 0x00, 0x03, 0x00, 0x6a, 0x00,
+    0x0a, 0x54, 0x65, 0x73, 0x74, 0x20, 0x41, 0x6c, 0x62, 0x75, 0x6d};
+
+// AVRCP Set Browsed Player Request with player_id = 2
+std::vector<uint8_t> set_browsed_player_request = {0x70, 0x00, 0x02, 0x00,
+                                                   0x02};
+
+// AVRCP Set Browsed Player Response with num items = 4 and depth = 0
+std::vector<uint8_t> set_browsed_player_response = {
+    0x70, 0x00, 0x0a, 0x04, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x04, 0x00, 0x6a, 0x00};
+
+// AVRCP Get Total Number of Items Request with Scope = Now Playing List
+std::vector<uint8_t> get_total_number_of_items_request = {0x75, 0x00, 0x01,
+                                                          0x03};
+
+// AVRCP Get Total number of Items Response with 5 items in folder
+std::vector<uint8_t> get_total_number_of_items_response = {
+    0x75, 0x00, 0x07, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05};
+
+// AVRCP Play Item Request with scope = Now Playing and
+// UID = 0x0000000000000003
+std::vector<uint8_t> play_item_request = {
+    0x00, 0x48, 0x00, 0x00, 0x19, 0x58, 0x74, 0x00, 0x00, 0x0b, 0x03,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00};
+
+// AVRCP Play Item Response
+std::vector<uint8_t> play_item_response = {0x09, 0x48, 0x00, 0x00, 0x19, 0x58,
+                                           0x74, 0x00, 0x00, 0x01, 0x04};
+
 }  // namespace
\ No newline at end of file
diff --git a/packet/tests/avrcp/change_path_packet_test.cc b/packet/tests/avrcp/change_path_packet_test.cc
new file mode 100644 (file)
index 0000000..1638c28
--- /dev/null
@@ -0,0 +1,76 @@
+/*
+ * Copyright 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <base/logging.h>
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+
+#include "avrcp_test_packets.h"
+#include "change_path.h"
+#include "packet_test_helper.h"
+
+namespace bluetooth {
+namespace avrcp {
+
+using TestChangePathReqPacket = TestPacketType<ChangePathRequest>;
+
+TEST(ChangePathResponseBuilderTest, builderTest) {
+  auto builder = ChangePathResponseBuilder::MakeBuilder(Status::NO_ERROR, 2);
+  ASSERT_EQ(builder->size(), change_path_response.size());
+
+  auto test_packet = TestChangePathReqPacket::Make();
+  builder->Serialize(test_packet);
+  ASSERT_EQ(test_packet->GetData(), change_path_response);
+}
+
+TEST(ChangePathResponseBuilderTest, builderErrorStatusTest) {
+  // NOTE: The num items in folder field doesn't matter when the status is
+  // not NO_ERROR
+  auto builder =
+      ChangePathResponseBuilder::MakeBuilder(Status::INVALID_DIRECTION, 2);
+  ASSERT_EQ(builder->size(), change_path_error_response.size());
+
+  auto test_packet = TestChangePathReqPacket::Make();
+  builder->Serialize(test_packet);
+  ASSERT_EQ(test_packet->GetData(), change_path_error_response);
+}
+
+TEST(ChangePathRequestTest, getterTest) {
+  auto test_packet = TestChangePathReqPacket::Make(change_path_request);
+
+  ASSERT_EQ(test_packet->GetUidCounter(), 0x0000u);
+  ASSERT_EQ(test_packet->GetDirection(), Direction::DOWN);
+  ASSERT_EQ(test_packet->GetUid(), 0x0000000000000002u);
+}
+
+TEST(ChangePathRequestTest, validTest) {
+  auto test_packet = TestChangePathReqPacket::Make(change_path_request);
+  ASSERT_TRUE(test_packet->IsValid());
+}
+
+TEST(ChangePathRequestTest, invalidTest) {
+  auto packet_copy = change_path_request;
+  packet_copy.push_back(0x00);
+  auto test_packet = TestChangePathReqPacket::Make(packet_copy);
+  ASSERT_FALSE(test_packet->IsValid());
+
+  std::vector<uint8_t> short_packet = {0x00, 0x01, 0x02, 0x03, 0x04};
+  test_packet = TestChangePathReqPacket::Make(short_packet);
+  ASSERT_FALSE(test_packet->IsValid());
+}
+
+}  // namespace avrcp
+}  // namespace bluetooth
\ No newline at end of file
index e6acccd..267c62b 100644 (file)
@@ -14,8 +14,6 @@
  * limitations under the License.
  */
 
-#include <base/logging.h>
-
 #include <gtest/gtest.h>
 
 #include "avrcp_test_packets.h"
index 10f1255..06a65d1 100644 (file)
@@ -14,8 +14,6 @@
  * limitations under the License.
  */
 
-#include <base/logging.h>
-
 #include <gtest/gtest.h>
 
 #include "avrcp_test_packets.h"
diff --git a/packet/tests/avrcp/get_folder_items_packet_test.cc b/packet/tests/avrcp/get_folder_items_packet_test.cc
new file mode 100644 (file)
index 0000000..152288c
--- /dev/null
@@ -0,0 +1,176 @@
+/*
+ * Copyright 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <gtest/gtest.h>
+
+#include "avrcp_test_packets.h"
+#include "get_folder_items.h"
+#include "packet_test_helper.h"
+
+namespace bluetooth {
+namespace avrcp {
+
+using TestGetFolderItemsReqPacket = TestPacketType<GetFolderItemsRequest>;
+
+TEST(GetFolderItemsResponseBuilderTest, builderMediaPlayerSizeTest) {
+  auto builder = GetFolderItemsResponseBuilder::MakePlayerListBuilder(
+      Status::NO_ERROR, 0x0000);
+  // If there are no items, then the only data in the packet is the status
+  ASSERT_EQ(builder->size(), get_folder_items_error_response.size());
+
+  auto player = MediaPlayerItem(0x0001, "com.google.android.music", true);
+  builder->AddMediaPlayer(player);
+  ASSERT_EQ(builder->size(), get_folder_items_media_player_response.size());
+}
+
+TEST(GetFolderItemsResponseBuilderTest, builderMediaPlayerAddTest) {
+  auto builder = GetFolderItemsResponseBuilder::MakePlayerListBuilder(
+      Status::NO_ERROR, 0x0000);
+  auto player = MediaPlayerItem(0x0001, "com.google.android.music", true);
+  builder->AddMediaPlayer(player);
+
+  auto test_packet = TestGetFolderItemsReqPacket::Make();
+  builder->Serialize(test_packet);
+  ASSERT_EQ(test_packet->GetData(), get_folder_items_media_player_response);
+}
+
+TEST(GetFolderItemsResponseBuilderTest, builderFolderSizeTest) {
+  auto builder =
+      GetFolderItemsResponseBuilder::MakeVFSBuilder(Status::NO_ERROR, 0x0000);
+  ASSERT_EQ(builder->size(), get_folder_items_error_response.size());
+
+  auto folder = FolderItem(0x0000000000000001, 0x00, true, "Test Folder");
+  builder->AddFolder(folder);
+  ASSERT_EQ(builder->size(), get_folder_items_folder_response.size());
+}
+
+TEST(GetFolderItemsResponseBuilderTest, builderFolderAddTest) {
+  auto builder =
+      GetFolderItemsResponseBuilder::MakeVFSBuilder(Status::NO_ERROR, 0x0000);
+  auto folder = FolderItem(0x0000000000000001, 0x00, true, "Test Folder");
+  builder->AddFolder(folder);
+
+  auto test_packet = TestGetFolderItemsReqPacket::Make();
+  builder->Serialize(test_packet);
+  ASSERT_EQ(test_packet->GetData(), get_folder_items_folder_response);
+}
+
+TEST(GetFolderItemsResponseBuilderTest, builderSongSizeTest) {
+  auto builder = GetFolderItemsResponseBuilder::MakeNowPlayingBuilder(
+      Status::NO_ERROR, 0x0000);
+  ASSERT_EQ(builder->size(), get_folder_items_error_response.size());
+
+  std::map<Attribute, std::string> attributes;
+  attributes.insert(AttributeEntry(Attribute::TITLE, "Test Title"));
+  auto song = MediaElementItem(0x02, "Test Title", attributes);
+  builder->AddSong(song);
+  ASSERT_EQ(builder->size(), get_folder_items_song_response.size());
+}
+
+TEST(GetFolderItemsResponseBuilderTest, builderSongAddTest) {
+  auto builder = GetFolderItemsResponseBuilder::MakeNowPlayingBuilder(
+      Status::NO_ERROR, 0x0000);
+  std::map<Attribute, std::string> attributes;
+  attributes.insert(AttributeEntry(Attribute::TITLE, "Test Title"));
+  auto song = MediaElementItem(0x02, "Test Title", attributes);
+  builder->AddSong(song);
+
+  auto test_packet = TestGetFolderItemsReqPacket::Make();
+  builder->Serialize(test_packet);
+  ASSERT_EQ(test_packet->GetData(), get_folder_items_song_response);
+}
+
+TEST(GetFolderItemsResponseBuilderTest, builderNoItemsTest) {
+  auto builder = GetFolderItemsResponseBuilder::MakePlayerListBuilder(
+      Status::NO_ERROR, 0x0000);
+  auto test_packet = TestGetFolderItemsReqPacket::Make();
+  builder->Serialize(test_packet);
+  ASSERT_EQ(test_packet->GetData(), get_folder_items_error_response);
+
+  builder =
+      GetFolderItemsResponseBuilder::MakeVFSBuilder(Status::NO_ERROR, 0x0000);
+  test_packet = TestGetFolderItemsReqPacket::Make();
+  builder->Serialize(test_packet);
+  ASSERT_EQ(test_packet->GetData(), get_folder_items_error_response);
+
+  builder = GetFolderItemsResponseBuilder::MakeNowPlayingBuilder(
+      Status::NO_ERROR, 0x0000);
+  test_packet = TestGetFolderItemsReqPacket::Make();
+  builder->Serialize(test_packet);
+  ASSERT_EQ(test_packet->GetData(), get_folder_items_error_response);
+}
+
+TEST(GetFolderItemsResponseBuilderTest, builderErrorStatusTest) {
+  std::vector<uint8_t> get_folder_items_inv_scope = {0x71, 0x00, 0x01, 0x0a};
+
+  auto builder = GetFolderItemsResponseBuilder::MakePlayerListBuilder(
+      Status::INVALID_SCOPE, 0x0000);
+
+  // Check that the status remains INVALID_SCOPE even though there are zero
+  // items
+  auto test_packet = TestGetFolderItemsReqPacket::Make();
+  builder->Serialize(test_packet);
+  ASSERT_EQ(test_packet->GetData(), get_folder_items_inv_scope);
+
+  auto player = MediaPlayerItem(0x0001, "com.google.android.music", true);
+  builder->AddMediaPlayer(player);
+
+  // Check to make sure that even though we added an item, it doesn't get
+  // written to the packet
+  test_packet = TestGetFolderItemsReqPacket::Make();
+  builder->Serialize(test_packet);
+  ASSERT_EQ(test_packet->GetData(), get_folder_items_inv_scope);
+}
+
+TEST(GetFolderItemsResponseBuilderTest, builderDeathTest) {
+  auto player = MediaPlayerItem(0x0001, "com.google.android.music", true);
+  auto folder = FolderItem(0x01, 0x00, true, "test folder");
+  auto song =
+      MediaElementItem(0x01, "test song", std::map<Attribute, std::string>());
+
+  auto builder = GetFolderItemsResponseBuilder::MakePlayerListBuilder(
+      Status::NO_ERROR, 0x0000);
+  ASSERT_DEATH(builder->AddFolder(folder), "scope_ == Scope::VFS");
+  ASSERT_DEATH(builder->AddSong(song),
+               "scope_ == Scope::VFS \\|\\| scope_ == Scope::NOW_PLAYING");
+
+  builder =
+      GetFolderItemsResponseBuilder::MakeVFSBuilder(Status::NO_ERROR, 0x0000);
+  ASSERT_DEATH(builder->AddMediaPlayer(player),
+               "scope_ == Scope::MEDIA_PLAYER_LIST");
+
+  builder = GetFolderItemsResponseBuilder::MakeNowPlayingBuilder(
+      Status::NO_ERROR, 0x0000);
+  ASSERT_DEATH(builder->AddMediaPlayer(player),
+               "scope_ == Scope::MEDIA_PLAYER_LIST");
+  ASSERT_DEATH(builder->AddFolder(folder), "scope_ == Scope::VFS");
+}
+
+TEST(GetFolderItemsRequestTest, getterTest) {
+  auto test_packet =
+      TestGetFolderItemsReqPacket::Make(get_folder_items_request_vfs);
+
+  ASSERT_EQ(test_packet->GetScope(), Scope::VFS);
+  ASSERT_EQ(test_packet->GetStartItem(), 0x00000000u);
+  ASSERT_EQ(test_packet->GetEndItem(), 0x00000005u);
+  ASSERT_EQ(test_packet->GetNumAttributes(), 1);
+
+  std::vector<Attribute> attribute_list = {Attribute::TITLE};
+  ASSERT_EQ(test_packet->GetAttributesRequested(), attribute_list);
+}
+
+}  // namespace avrcp
+}  // namespace bluetooth
\ No newline at end of file
diff --git a/packet/tests/avrcp/get_item_attributes_packet_test.cc b/packet/tests/avrcp/get_item_attributes_packet_test.cc
new file mode 100644 (file)
index 0000000..64dff86
--- /dev/null
@@ -0,0 +1,103 @@
+/*
+ * Copyright 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <gtest/gtest.h>
+
+#include "avrcp_test_packets.h"
+#include "get_item_attributes.h"
+#include "packet_test_helper.h"
+
+namespace bluetooth {
+namespace avrcp {
+
+using TestGetItemAttrsReqPacket = TestPacketType<GetItemAttributesRequest>;
+
+TEST(GetItemAttributesResponseBuilderTest, builderSizeTest) {
+  auto builder =
+      GetItemAttributesResponseBuilder::MakeBuilder(Status::NO_ERROR);
+  ASSERT_EQ(builder->size(), 5u);
+
+  builder->AddAttributeEntry(Attribute::TITLE, "Test Song");
+  ASSERT_EQ(builder->size(), 22u);
+
+  builder->AddAttributeEntry(Attribute::ARTIST_NAME, "Test Artist");
+  ASSERT_EQ(builder->size(), 41u);
+
+  builder->AddAttributeEntry(Attribute::ALBUM_NAME, "Test Album");
+  ASSERT_EQ(builder->size(), get_item_attributes_song_response.size());
+}
+
+TEST(GetItemAttributesResponseBuilderTest, builderTest) {
+  auto builder =
+      GetItemAttributesResponseBuilder::MakeBuilder(Status::NO_ERROR);
+  builder->AddAttributeEntry(Attribute::TITLE, "Test Song");
+  builder->AddAttributeEntry(Attribute::ARTIST_NAME, "Test Artist");
+  builder->AddAttributeEntry(Attribute::ALBUM_NAME, "Test Album");
+
+  auto test_packet = TestGetItemAttrsReqPacket::Make();
+  builder->Serialize(test_packet);
+  ASSERT_EQ(test_packet->GetData(), get_item_attributes_song_response);
+}
+
+TEST(GetItemAttributesResponseBuilderTest, errorStatusTest) {
+  std::vector<uint8_t> does_not_exist_status = {0x73, 0x00, 0x01, 0x09};
+  auto builder =
+      GetItemAttributesResponseBuilder::MakeBuilder(Status::DOES_NOT_EXIST);
+  ASSERT_EQ(builder->size(), does_not_exist_status.size());
+
+  auto test_packet = TestGetItemAttrsReqPacket::Make();
+  builder->Serialize(test_packet);
+  ASSERT_EQ(test_packet->GetData(), does_not_exist_status);
+}
+
+TEST(GetItemAttributesRequestTest, getterTest) {
+  auto test_packet = TestGetItemAttrsReqPacket::Make(
+      get_item_attributes_request_all_attributes);
+
+  ASSERT_EQ(test_packet->GetScope(), Scope::NOW_PLAYING);
+  ASSERT_EQ(test_packet->GetUidCounter(), 0x0000u);
+  ASSERT_EQ(test_packet->GetUid(), 0x0000000000000001u);
+  ASSERT_EQ(test_packet->GetNumAttributes(), 7);
+  std::vector<Attribute> attrs_requested = {Attribute::TITLE,
+                                            Attribute::ARTIST_NAME,
+                                            Attribute::ALBUM_NAME,
+                                            Attribute::TRACK_NUMBER,
+                                            Attribute::TOTAL_NUMBER_OF_TRACKS,
+                                            Attribute::GENRE,
+                                            Attribute::PLAYING_TIME};
+  ASSERT_EQ(test_packet->GetAttributesRequested(), attrs_requested);
+}
+
+TEST(GetItemAttributesRequestTest, validTest) {
+  auto test_packet = TestGetItemAttrsReqPacket::Make(
+      get_item_attributes_request_all_attributes);
+  ASSERT_TRUE(test_packet->IsValid());
+}
+
+TEST(GetItemAttributesRequestTest, invalidTest) {
+  auto packet_copy = get_item_attributes_request_all_attributes;
+  packet_copy.push_back(0x00);
+  auto test_packet = TestGetItemAttrsReqPacket::Make(packet_copy);
+  ASSERT_FALSE(test_packet->IsValid());
+
+  std::vector<uint8_t> short_packet = {0x00, 0x01, 0x02, 0x03,
+                                       0x04, 0x05, 0x06, 0x07};
+  test_packet = TestGetItemAttrsReqPacket::Make(short_packet);
+  ASSERT_FALSE(test_packet->IsValid());
+}
+
+}  // namespace avrcp
+}  // namespace bluetooth
\ No newline at end of file
index afe7380..c15147d 100644 (file)
@@ -14,8 +14,6 @@
  * limitations under the License.
  */
 
-#include <base/logging.h>
-
 #include <gtest/gtest.h>
 
 #include "avrcp_test_packets.h"
diff --git a/packet/tests/avrcp/get_total_number_of_items_packet_test.cc b/packet/tests/avrcp/get_total_number_of_items_packet_test.cc
new file mode 100644 (file)
index 0000000..cffc2a8
--- /dev/null
@@ -0,0 +1,73 @@
+/*
+ * Copyright 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <gtest/gtest.h>
+
+#include "avrcp_test_packets.h"
+#include "get_total_number_of_items.h"
+#include "packet_test_helper.h"
+
+namespace bluetooth {
+namespace avrcp {
+
+using TestGetTotalNumItemsReqPacket =
+    TestPacketType<GetTotalNumberOfItemsRequest>;
+
+TEST(GetTotalNumberOfItemsResponseBuilderTest, builderTest) {
+  auto builder = GetTotalNumberOfItemsResponseBuilder::MakeBuilder(
+      Status::NO_ERROR, 0x0000u, 0x00000005u);
+  ASSERT_EQ(builder->size(), get_total_number_of_items_response.size());
+
+  auto test_packet = TestGetTotalNumItemsReqPacket::Make();
+  builder->Serialize(test_packet);
+  ASSERT_EQ(test_packet->GetData(), get_total_number_of_items_response);
+}
+
+TEST(GetTotalNumberOfItemsResponseBuilderTest, errorStatusTest) {
+  std::vector<uint8_t> inv_scope_status_packet = {0x75, 0x00, 0x01, 0x0a};
+  auto builder = GetTotalNumberOfItemsResponseBuilder::MakeBuilder(
+      Status::INVALID_SCOPE, 0x1234u, 0x56789abcu);
+  ASSERT_EQ(builder->size(), inv_scope_status_packet.size());
+
+  auto test_packet = TestGetTotalNumItemsReqPacket::Make();
+  builder->Serialize(test_packet);
+  ASSERT_EQ(test_packet->GetData(), inv_scope_status_packet);
+}
+
+TEST(GetTotalNumberOfItemsRequestTest, getterTest) {
+  auto test_packet =
+      TestGetTotalNumItemsReqPacket::Make(get_total_number_of_items_request);
+  ASSERT_EQ(test_packet->GetScope(), Scope::NOW_PLAYING);
+}
+
+TEST(GetTotalNumberOfItemsRequestTest, validTest) {
+  auto test_packet =
+      TestGetTotalNumItemsReqPacket::Make(get_total_number_of_items_request);
+  ASSERT_TRUE(test_packet->IsValid());
+}
+
+TEST(GetTotalNumberOfItemsRequestTest, invalidTest) {
+  auto packet_copy = get_total_number_of_items_request;
+  packet_copy.push_back(0x00);
+  auto test_packet = TestGetTotalNumItemsReqPacket::Make(packet_copy);
+  ASSERT_FALSE(test_packet->IsValid());
+
+  std::vector<uint8_t> short_packet = {0x00, 0x01, 0x02, 0x03};
+  ASSERT_FALSE(test_packet->IsValid());
+}
+
+}  // namespace avrcp
+}  // namespace bluetooth
\ No newline at end of file
index f9b76f9..0ef2879 100644 (file)
@@ -14,8 +14,6 @@
  * limitations under the License.
  */
 
-#include <base/logging.h>
-
 #include <gtest/gtest.h>
 
 #include "avrcp_test_packets.h"
diff --git a/packet/tests/avrcp/play_item_packet_test.cc b/packet/tests/avrcp/play_item_packet_test.cc
new file mode 100644 (file)
index 0000000..f2e48aa
--- /dev/null
@@ -0,0 +1,63 @@
+/*
+ * Copyright 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <gtest/gtest.h>
+
+#include "avrcp_test_packets.h"
+#include "packet_test_helper.h"
+#include "play_item.h"
+
+namespace bluetooth {
+namespace avrcp {
+
+using TestPlayItemReqPacket = TestPacketType<PlayItemRequest>;
+
+TEST(PlayItemResponseBuilderTest, builderTest) {
+  auto builder = PlayItemResponseBuilder::MakeBuilder(Status::NO_ERROR);
+  ASSERT_EQ(builder->size(), play_item_response.size());
+
+  auto test_packet = TestPlayItemReqPacket::Make();
+  builder->Serialize(test_packet);
+  ASSERT_EQ(test_packet->GetData(), play_item_response);
+}
+
+TEST(PlayItemResponseTest, getterTest) {
+  auto test_packet = TestPlayItemReqPacket::Make(play_item_request);
+
+  ASSERT_EQ(test_packet->GetScope(), Scope::NOW_PLAYING);
+  ASSERT_EQ(test_packet->GetUid(), 0x0000000000000003u);
+  ASSERT_EQ(test_packet->GetUidCounter(), 0x0000u);
+}
+
+TEST(PlayItemResponseTest, validTest) {
+  auto test_packet = TestPlayItemReqPacket::Make(play_item_request);
+
+  ASSERT_TRUE(test_packet->IsValid());
+}
+
+TEST(PlayItemResponseTest, invalidTest) {
+  auto packet_copy = play_item_request;
+  packet_copy.push_back(0x00);
+  auto test_packet = TestPlayItemReqPacket::Make(packet_copy);
+  ASSERT_FALSE(test_packet->IsValid());
+
+  std::vector<uint8_t> short_packet = {0x00, 0x01, 0x02, 0x03, 0x04};
+  test_packet = TestPlayItemReqPacket::Make(short_packet);
+  ASSERT_FALSE(test_packet->IsValid());
+}
+
+}  // namespace avrcp
+}  // namespace bluetooth
index 831e994..7897587 100644 (file)
@@ -14,8 +14,6 @@
  * limitations under the License.
  */
 
-#include <base/logging.h>
-
 #include <gtest/gtest.h>
 
 #include "avrcp_test_packets.h"
diff --git a/packet/tests/avrcp/set_browsed_player_packet_test.cc b/packet/tests/avrcp/set_browsed_player_packet_test.cc
new file mode 100644 (file)
index 0000000..828df18
--- /dev/null
@@ -0,0 +1,74 @@
+/*
+ * Copyright 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <gtest/gtest.h>
+
+#include "avrcp_test_packets.h"
+#include "packet_test_helper.h"
+#include "set_browsed_player.h"
+
+namespace bluetooth {
+namespace avrcp {
+
+using TestSetBrowsedPlayerPacket = TestPacketType<SetBrowsedPlayerRequest>;
+
+TEST(SetBrowsedPlayerResponseBuilder, builderTest) {
+  auto builder = SetBrowsedPlayerResponseBuilder::MakeBuilder(Status::NO_ERROR,
+                                                              0x0000, 4, 0, "");
+  ASSERT_EQ(builder->size(), set_browsed_player_response.size());
+
+  auto test_packet = TestSetBrowsedPlayerPacket::Make();
+  builder->Serialize(test_packet);
+  ASSERT_EQ(test_packet->GetData(), set_browsed_player_response);
+}
+
+TEST(SetBrowsedPlayerResponseBuilder, errorStatusTest) {
+  std::vector<uint8_t> player_not_browsable_status = {0x70, 0x00, 0x01, 0x12};
+  auto builder = SetBrowsedPlayerResponseBuilder::MakeBuilder(
+      Status::PLAYER_NOT_BROWSABLE, 0x1234, 5, 6, "Field Not Used");
+  ASSERT_EQ(builder->size(), player_not_browsable_status.size());
+
+  auto test_packet = TestSetBrowsedPlayerPacket::Make();
+  builder->Serialize(test_packet);
+  ASSERT_EQ(test_packet->GetData(), player_not_browsable_status);
+}
+
+TEST(SetBrowsedPlayerRequestTest, getterTest) {
+  auto test_packet =
+      TestSetBrowsedPlayerPacket::Make(set_browsed_player_request);
+
+  ASSERT_EQ(test_packet->GetPlayerId(), 0x0002u);
+}
+
+TEST(SetBrowsedPlayerRequestTest, validTest) {
+  auto test_packet =
+      TestSetBrowsedPlayerPacket::Make(set_browsed_player_request);
+  ASSERT_TRUE(test_packet->IsValid());
+}
+
+TEST(SetBrowsedPlayerRequestTest, invalidTest) {
+  auto packet_copy = set_browsed_player_request;
+  packet_copy.push_back(0x00);
+  auto test_packet = TestSetBrowsedPlayerPacket::Make(packet_copy);
+  ASSERT_FALSE(test_packet->IsValid());
+
+  std::vector<uint8_t> short_packet = {0x00, 0x01, 0x02, 0x03, 0x04};
+  test_packet = TestSetBrowsedPlayerPacket::Make(short_packet);
+  ASSERT_FALSE(test_packet->IsValid());
+}
+
+}  // namespace avrcp
+}  // namespace bluetooth
\ No newline at end of file
index aec8334..e933824 100644 (file)
  * limitations under the License.
  */
 
-#include <base/logging.h>
+#include <tuple>
 
 #include <gtest/gtest.h>
-#include <tuple>
 
 #include "avrcp_test_packets.h"
 #include "packet_test_helper.h"
index 8f33c19..5794686 100644 (file)
@@ -14,7 +14,6 @@
  * limitations under the License.
  */
 
-#include <base/logging.h>
 #include <gtest/gtest.h>
 #include <memory>
 
index 60f462e..2c4c147 100644 (file)
@@ -14,7 +14,6 @@
  * limitations under the License.
  */
 
-#include <base/logging.h>
 #include <gtest/gtest.h>
 
 #include "packet.h"
index a3fac99..2d82bee 100755 (executable)
@@ -30,7 +30,6 @@ HOST_TESTS = [
 
 SOONG_UI_BASH = 'build/soong/soong_ui.bash'
 
-
 def str2bool(argument, default=False):
   """ Convert a string to a booleen value. """
   argument = str(argument)