• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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