Thu, 22 Jan 2015 13:21:57 +0100
Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6
1 /* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */
2 /* vim: set ts=2 et sw=2 tw=80: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this file,
5 * You can obtain one at http://mozilla.org/MPL/2.0/. */
7 #include "base/basictypes.h"
9 #include "BluetoothReplyRunnable.h"
10 #include "BluetoothService.h"
11 #include "BluetoothUtils.h"
12 #include "jsapi.h"
13 #include "mozilla/Scoped.h"
14 #include "mozilla/dom/bluetooth/BluetoothTypes.h"
15 #include "nsContentUtils.h"
16 #include "nsCxPusher.h"
17 #include "nsIScriptContext.h"
18 #include "nsISystemMessagesInternal.h"
19 #include "nsString.h"
20 #include "nsTArray.h"
21 #include "nsServiceManagerUtils.h"
23 BEGIN_BLUETOOTH_NAMESPACE
25 bool
26 SetJsObject(JSContext* aContext,
27 const BluetoothValue& aValue,
28 JS::Handle<JSObject*> aObj)
29 {
30 MOZ_ASSERT(aContext && aObj);
32 if (aValue.type() != BluetoothValue::TArrayOfBluetoothNamedValue) {
33 BT_WARNING("SetJsObject: Invalid parameter type");
34 return false;
35 }
37 const nsTArray<BluetoothNamedValue>& arr =
38 aValue.get_ArrayOfBluetoothNamedValue();
40 for (uint32_t i = 0; i < arr.Length(); i++) {
41 JS::Rooted<JS::Value> val(aContext);
42 const BluetoothValue& v = arr[i].value();
44 switch(v.type()) {
45 case BluetoothValue::TnsString: {
46 JSString* jsData = JS_NewUCStringCopyN(aContext,
47 v.get_nsString().BeginReading(),
48 v.get_nsString().Length());
49 NS_ENSURE_TRUE(jsData, false);
50 val = STRING_TO_JSVAL(jsData);
51 break;
52 }
53 case BluetoothValue::Tuint32_t:
54 val = INT_TO_JSVAL(v.get_uint32_t());
55 break;
56 case BluetoothValue::Tbool:
57 val = BOOLEAN_TO_JSVAL(v.get_bool());
58 break;
59 default:
60 BT_WARNING("SetJsObject: Parameter is not handled");
61 break;
62 }
64 if (!JS_SetProperty(aContext, aObj,
65 NS_ConvertUTF16toUTF8(arr[i].name()).get(),
66 val)) {
67 BT_WARNING("Failed to set property");
68 return false;
69 }
70 }
72 return true;
73 }
75 nsString
76 GetObjectPathFromAddress(const nsAString& aAdapterPath,
77 const nsAString& aDeviceAddress)
78 {
79 // The object path would be like /org/bluez/2906/hci0/dev_00_23_7F_CB_B4_F1,
80 // and the adapter path would be the first part of the object path, according
81 // to the example above, it's /org/bluez/2906/hci0.
82 nsString devicePath(aAdapterPath);
83 devicePath.AppendLiteral("/dev_");
84 devicePath.Append(aDeviceAddress);
85 devicePath.ReplaceChar(':', '_');
86 return devicePath;
87 }
89 nsString
90 GetAddressFromObjectPath(const nsAString& aObjectPath)
91 {
92 // The object path would be like /org/bluez/2906/hci0/dev_00_23_7F_CB_B4_F1,
93 // and the adapter path would be the first part of the object path, according
94 // to the example above, it's /org/bluez/2906/hci0.
95 nsString address(aObjectPath);
96 int addressHead = address.RFind("/") + 5;
98 MOZ_ASSERT(addressHead + BLUETOOTH_ADDRESS_LENGTH == (int)address.Length());
100 address.Cut(0, addressHead);
101 address.ReplaceChar('_', ':');
103 return address;
104 }
106 bool
107 BroadcastSystemMessage(const nsAString& aType,
108 const InfallibleTArray<BluetoothNamedValue>& aData)
109 {
110 mozilla::AutoSafeJSContext cx;
111 NS_ASSERTION(!::JS_IsExceptionPending(cx),
112 "Shouldn't get here when an exception is pending!");
114 JS::Rooted<JSObject*> obj(cx, JS_NewObject(cx, nullptr, JS::NullPtr(),
115 JS::NullPtr()));
116 if (!obj) {
117 BT_WARNING("Failed to new JSObject for system message!");
118 return false;
119 }
121 if (!SetJsObject(cx, aData, obj)) {
122 BT_WARNING("Failed to set properties of system message!");
123 return false;
124 }
126 nsCOMPtr<nsISystemMessagesInternal> systemMessenger =
127 do_GetService("@mozilla.org/system-message-internal;1");
128 NS_ENSURE_TRUE(systemMessenger, false);
130 JS::Rooted<JS::Value> value(cx, JS::ObjectValue(*obj));
131 systemMessenger->BroadcastMessage(aType, value,
132 JS::UndefinedHandleValue);
134 return true;
135 }
137 void
138 DispatchBluetoothReply(BluetoothReplyRunnable* aRunnable,
139 const BluetoothValue& aValue,
140 const nsAString& aErrorStr)
141 {
142 // Reply will be deleted by the runnable after running on main thread
143 BluetoothReply* reply;
144 if (!aErrorStr.IsEmpty()) {
145 nsString err(aErrorStr);
146 reply = new BluetoothReply(BluetoothReplyError(err));
147 } else {
148 MOZ_ASSERT(aValue.type() != BluetoothValue::T__None);
149 reply = new BluetoothReply(BluetoothReplySuccess(aValue));
150 }
152 aRunnable->SetReply(reply);
153 if (NS_FAILED(NS_DispatchToMainThread(aRunnable))) {
154 BT_WARNING("Failed to dispatch to main thread!");
155 }
156 }
158 void
159 ParseAtCommand(const nsACString& aAtCommand, const int aStart,
160 nsTArray<nsCString>& aRetValues)
161 {
162 int length = aAtCommand.Length();
163 int begin = aStart;
165 for (int i = aStart; i < length; ++i) {
166 // Use ',' as separator
167 if (aAtCommand[i] == ',') {
168 nsCString tmp(nsDependentCSubstring(aAtCommand, begin, i - begin));
169 aRetValues.AppendElement(tmp);
171 begin = i + 1;
172 }
173 }
175 nsCString tmp(nsDependentCSubstring(aAtCommand, begin));
176 aRetValues.AppendElement(tmp);
177 }
179 void
180 DispatchStatusChangedEvent(const nsAString& aType,
181 const nsAString& aAddress,
182 bool aStatus)
183 {
184 MOZ_ASSERT(NS_IsMainThread());
186 InfallibleTArray<BluetoothNamedValue> data;
187 data.AppendElement(
188 BluetoothNamedValue(NS_LITERAL_STRING("address"), nsString(aAddress)));
189 data.AppendElement(
190 BluetoothNamedValue(NS_LITERAL_STRING("status"), aStatus));
192 BluetoothSignal signal(nsString(aType), NS_LITERAL_STRING(KEY_ADAPTER), data);
194 BluetoothService* bs = BluetoothService::Get();
195 NS_ENSURE_TRUE_VOID(bs);
196 bs->DistributeSignal(signal);
197 }
199 END_BLUETOOTH_NAMESPACE