1 /*
2 * Copyright 2021 HIMSA II K/S - www.himsa.com.
3 * Represented by EHIMA - www.ehima.com
4 *
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 */
17
18 #include <base/functional/bind.h>
19 #include <base/location.h>
20 #include <base/logging.h>
21 #include <hardware/bluetooth.h>
22 #include <hardware/bt_csis.h>
23
24 #include "bind_helpers.h"
25 #include "bta_csis_api.h"
26 #include "btif_common.h"
27 #include "btif_profile_storage.h"
28 #include "stack/include/btu.h"
29
30 using base::Bind;
31 using base::Owned;
32 using base::Passed;
33 using base::Unretained;
34 using bluetooth::csis::ConnectionState;
35 using bluetooth::csis::CsisClientCallbacks;
36 using bluetooth::csis::CsisClientInterface;
37 using bluetooth::csis::CsisGroupLockStatus;
38
39 using bluetooth::csis::CsisClient;
40
41 namespace {
42 std::unique_ptr<CsisClientInterface> csis_client_instance;
43 std::atomic_bool initialized = false;
44
45 class CsipSetCoordinatorServiceInterfaceImpl : public CsisClientInterface,
46 public CsisClientCallbacks {
47 ~CsipSetCoordinatorServiceInterfaceImpl() override = default;
48
Init(CsisClientCallbacks * callbacks)49 void Init(CsisClientCallbacks* callbacks) override {
50 DVLOG(2) << __func__;
51 this->callbacks_ = callbacks;
52
53 do_in_main_thread(
54 FROM_HERE,
55 Bind(&CsisClient::Initialize, this,
56 jni_thread_wrapper(FROM_HERE,
57 Bind(&btif_storage_load_bonded_csis_devices))));
58 /* It might be not yet initialized, but setting this flag here is safe,
59 * because other calls will check this and the native instance
60 */
61 initialized = true;
62 }
63
Connect(const RawAddress & addr)64 void Connect(const RawAddress& addr) override {
65 if (!initialized || !CsisClient::IsCsisClientRunning()) {
66 DVLOG(2) << __func__
67 << " call ignored, due to already started cleanup procedure or "
68 "service being not read";
69 return;
70 }
71
72 DVLOG(2) << __func__ << " addr: " << ADDRESS_TO_LOGGABLE_STR(addr);
73 do_in_main_thread(FROM_HERE, Bind(&CsisClient::Connect,
74 Unretained(CsisClient::Get()), addr));
75 }
76
Disconnect(const RawAddress & addr)77 void Disconnect(const RawAddress& addr) override {
78 if (!initialized || !CsisClient::IsCsisClientRunning()) {
79 DVLOG(2) << __func__
80 << " call ignored, due to already started cleanup procedure or "
81 "service being not read";
82 return;
83 }
84
85 DVLOG(2) << __func__ << " addr: " << ADDRESS_TO_LOGGABLE_STR(addr);
86 do_in_main_thread(FROM_HERE, Bind(&CsisClient::Disconnect,
87 Unretained(CsisClient::Get()), addr));
88 }
89
RemoveDevice(const RawAddress & addr)90 void RemoveDevice(const RawAddress& addr) override {
91 if (!initialized || !CsisClient::IsCsisClientRunning()) {
92 DVLOG(2) << __func__
93 << " call ignored, due to already started cleanup procedure or "
94 "service being not ready";
95
96 /* Clear storage */
97 do_in_jni_thread(FROM_HERE, Bind(&btif_storage_remove_csis_device, addr));
98 return;
99 }
100
101 DVLOG(2) << __func__ << " addr: " << ADDRESS_TO_LOGGABLE_STR(addr);
102 do_in_main_thread(FROM_HERE, Bind(&CsisClient::RemoveDevice,
103 Unretained(CsisClient::Get()), addr));
104 /* Clear storage */
105 do_in_jni_thread(FROM_HERE, Bind(&btif_storage_remove_csis_device, addr));
106 }
107
LockGroup(int group_id,bool lock)108 void LockGroup(int group_id, bool lock) override {
109 if (!initialized || !CsisClient::IsCsisClientRunning()) {
110 DVLOG(2) << __func__
111 << " call ignored, due to already started cleanup procedure or "
112 "service being not read";
113 return;
114 }
115
116 DVLOG(2) << __func__ << " group id: " << group_id << " lock: " << lock;
117 do_in_main_thread(
118 FROM_HERE, Bind(&CsisClient::LockGroup, Unretained(CsisClient::Get()),
119 group_id, lock, base::DoNothing()));
120 }
121
Cleanup(void)122 void Cleanup(void) override {
123 if (!initialized || !CsisClient::IsCsisClientRunning()) {
124 DVLOG(2) << __func__
125 << " call ignored, due to already started cleanup procedure or "
126 "service being not read";
127 return;
128 }
129
130 DVLOG(2) << __func__;
131 initialized = false;
132 do_in_main_thread(FROM_HERE, Bind(&CsisClient::CleanUp));
133 }
134
OnConnectionState(const RawAddress & addr,ConnectionState state)135 void OnConnectionState(const RawAddress& addr,
136 ConnectionState state) override {
137 DVLOG(2) << __func__ << " addr: " << ADDRESS_TO_LOGGABLE_STR(addr);
138 do_in_jni_thread(FROM_HERE, Bind(&CsisClientCallbacks::OnConnectionState,
139 Unretained(callbacks_), addr, state));
140 }
141
OnDeviceAvailable(const RawAddress & addr,int group_id,int group_size,int rank,const bluetooth::Uuid & uuid)142 void OnDeviceAvailable(const RawAddress& addr, int group_id, int group_size,
143 int rank, const bluetooth::Uuid& uuid) override {
144 DVLOG(2) << __func__ << " addr: " << ADDRESS_TO_LOGGABLE_STR(addr)
145 << " group_id: " << group_id;
146
147 do_in_jni_thread(FROM_HERE, Bind(&CsisClientCallbacks::OnDeviceAvailable,
148 Unretained(callbacks_), addr, group_id,
149 group_size, rank, uuid));
150 }
151
OnSetMemberAvailable(const RawAddress & addr,int group_id)152 void OnSetMemberAvailable(const RawAddress& addr, int group_id) override {
153 DVLOG(2) << __func__ << " addr: " << ADDRESS_TO_LOGGABLE_STR(addr)
154 << " group id: " << group_id;
155
156 do_in_jni_thread(FROM_HERE, Bind(&CsisClientCallbacks::OnSetMemberAvailable,
157 Unretained(callbacks_), addr, group_id));
158 }
159
160 /* Callback for lock changed in the group */
OnGroupLockChanged(int group_id,bool locked,CsisGroupLockStatus status)161 virtual void OnGroupLockChanged(int group_id, bool locked,
162 CsisGroupLockStatus status) override {
163 DVLOG(2) << __func__ << " group id: " << group_id << " lock: " << locked
164 << " status: " << int(status);
165
166 do_in_jni_thread(FROM_HERE,
167 Bind(&CsisClientCallbacks::OnGroupLockChanged,
168 Unretained(callbacks_), group_id, locked, status));
169 }
170
171 private:
172 CsisClientCallbacks* callbacks_;
173 };
174
175 } /* namespace */
176
btif_csis_client_get_interface(void)177 CsisClientInterface* btif_csis_client_get_interface(void) {
178 if (!csis_client_instance)
179 csis_client_instance.reset(new CsipSetCoordinatorServiceInterfaceImpl());
180
181 return csis_client_instance.get();
182 }
183