1// Copyright 2014 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "device/nfc/nfc_tag_chromeos.h"
6
7#include "chromeos/dbus/dbus_thread_manager.h"
8#include "device/nfc/nfc_tag_technology_chromeos.h"
9#include "third_party/cros_system_api/dbus/service_constants.h"
10
11using device::NfcTag;
12using device::NfcTagTechnology;
13using device::NfcNdefTagTechnology;
14
15namespace chromeos {
16
17namespace {
18
19// Converts an NFC tag type value returned by neard to a NfcTag::TagType enum
20// value.
21NfcTag::TagType DBusTypePropertyToTagType(const std::string& type) {
22  if (type == nfc_tag::kTagType1)
23    return NfcTag::kTagType1;
24  if (type == nfc_tag::kTagType2)
25    return NfcTag::kTagType2;
26  if (type == nfc_tag::kTagType3)
27    return NfcTag::kTagType3;
28  if (type == nfc_tag::kTagType4)
29    return NfcTag::kTagType4;
30  return NfcTag::kTagTypeUnknown;
31}
32
33// Converts an NFC tag protocol value returned by neard to a NfcTag::Protocol
34// enum value.
35NfcTag::Protocol DBusProtocolPropertyToTagProtocol(
36    const std::string& protocol) {
37  if (protocol == nfc_common::kProtocolFelica)
38    return NfcTag::kProtocolFelica;
39  if (protocol == nfc_common::kProtocolIsoDep)
40    return NfcTag::kProtocolIsoDep;
41  if (protocol == nfc_common::kProtocolJewel)
42    return NfcTag::kProtocolJewel;
43  if (protocol == nfc_common::kProtocolMifare)
44    return NfcTag::kProtocolMifare;
45  if (protocol == nfc_common::kProtocolNfcDep)
46    return NfcTag::kProtocolNfcDep;
47  return NfcTag::kProtocolUnknown;
48}
49
50}  // namespace
51
52NfcTagChromeOS::NfcTagChromeOS(const dbus::ObjectPath& object_path)
53    : object_path_(object_path),
54      is_ready_(false),
55      ndef_technology_(new NfcNdefTagTechnologyChromeOS(this)) {
56  DBusThreadManager::Get()->GetNfcTagClient()->AddObserver(this);
57}
58
59NfcTagChromeOS::~NfcTagChromeOS() {
60  DBusThreadManager::Get()->GetNfcTagClient()->RemoveObserver(this);
61}
62
63void NfcTagChromeOS::AddObserver(NfcTag::Observer* observer) {
64  observers_.AddObserver(observer);
65}
66
67void NfcTagChromeOS::RemoveObserver(NfcTag::Observer* observer) {
68  observers_.RemoveObserver(observer);
69}
70
71std::string NfcTagChromeOS::GetIdentifier() const {
72  return object_path_.value();
73}
74
75NfcTag::TagType NfcTagChromeOS::GetType() const {
76  DCHECK(object_path_.IsValid());
77  return DBusTypePropertyToTagType(
78      DBusThreadManager::Get()->GetNfcTagClient()->
79          GetProperties(object_path_)->type.value());
80}
81
82bool NfcTagChromeOS::IsReadOnly() const {
83  DCHECK(object_path_.IsValid());
84  return DBusThreadManager::Get()->GetNfcTagClient()->
85      GetProperties(object_path_)->read_only.value();
86}
87
88NfcTag::Protocol NfcTagChromeOS::GetSupportedProtocol() const {
89  DCHECK(object_path_.IsValid());
90  return DBusProtocolPropertyToTagProtocol(
91      DBusThreadManager::Get()->GetNfcTagClient()->
92          GetProperties(object_path_)->protocol.value());
93}
94
95NfcTagTechnology::TechnologyTypeMask
96NfcTagChromeOS::GetSupportedTechnologies() const {
97  // Determine supported technologies based on the tag's protocol and
98  // type.
99  NfcTag::TagType type = GetType();
100  NfcTag::Protocol protocol = GetSupportedProtocol();
101  if (type == NfcTag::kTagTypeUnknown || protocol == kProtocolUnknown) {
102    VLOG(1) << "Tag type and protocol unknown.";
103    return 0;
104  }
105
106  NfcTagTechnology::TechnologyTypeMask technologies = 0;
107  technologies |= NfcTagTechnology::kTechnologyTypeNdef;
108  if (type == NfcTag::kTagType3) {
109    DCHECK(protocol == NfcTag::kProtocolFelica);
110    return technologies | NfcTagTechnology::kTechnologyTypeNfcF;
111  }
112
113  if (protocol == NfcTag::kProtocolIsoDep) {
114    DCHECK(type == NfcTag::kTagType4);
115    technologies |= NfcTagTechnology::kTechnologyTypeIsoDep;
116    // TODO(armansito): Neard doesn't provide enough information to determine
117    // if the underlying wave-form is type A or type B. For now, report
118    // neither.
119    return technologies;
120  }
121
122  return technologies | NfcTagTechnology::kTechnologyTypeNfcA;
123}
124
125bool NfcTagChromeOS::IsReady() const {
126  return is_ready_;
127}
128
129NfcNdefTagTechnology* NfcTagChromeOS::GetNdefTagTechnology() {
130  return ndef_technology_.get();
131}
132
133void NfcTagChromeOS::TagPropertyChanged(const dbus::ObjectPath& object_path,
134                                        const std::string& property_name) {
135  if (object_path != object_path_)
136    return;
137
138  NfcTagClient::Properties* properties =
139    DBusThreadManager::Get()->GetNfcTagClient()->GetProperties(object_path_);
140  DCHECK(properties);
141
142  if (property_name == properties->type.name()) {
143    FOR_EACH_OBSERVER(NfcTag::Observer, observers_,
144                      TagTypeChanged(this, GetType()));
145  } else if (property_name == properties->read_only.name()) {
146    FOR_EACH_OBSERVER(NfcTag::Observer, observers_,
147                      TagWritePermissionChanged(this, IsReadOnly()));
148  } else if (property_name == properties->protocol.name()) {
149    FOR_EACH_OBSERVER(
150        NfcTag::Observer, observers_,
151        TagSupportedProtocolChanged(this, GetSupportedProtocol()));
152  }
153}
154
155void NfcTagChromeOS::TagPropertiesReceived(
156    const dbus::ObjectPath& object_path) {
157  if (is_ready_ || object_path != object_path_)
158    return;
159
160  is_ready_ = true;
161  FOR_EACH_OBSERVER(NfcTag::Observer, observers_, TagReady(this));
162}
163
164}  // namespace chromeos
165