From 2bb7e256a171f5e322749cc96447ea942bbe7584 Mon Sep 17 00:00:00 2001 From: Erkki Silvola Date: Fri, 17 Apr 2020 14:08:48 +0300 Subject: [PATCH] android docs udpated --- .../docs/html/BDBleApiImpl_8java_source.html | 95 +++++++------- .../PolarBleApiDefaultImpl_8java_source.html | 2 +- .../docs/html/PolarBleApi_8java_source.html | 3 +- ...r_1_1com_1_1sdk_1_1api_1_1PolarBleApi.html | 34 +++++ ...lar_1_1com_1_1sdk_1_1api_1_1PolarBleApi.js | 1 + ...1_1com_1_1sdk_1_1impl_1_1BDBleApiImpl.html | 124 +++++++++++------- ...r_1_1com_1_1sdk_1_1impl_1_1BDBleApiImpl.js | 1 + polar-sdk-android/docs/html/functions.html | 4 + .../docs/html/functions_func.html | 4 + polar-sdk-android/docs/html/navtreedata.js | 2 +- polar-sdk-android/docs/html/navtreeindex0.js | 66 +++++----- polar-sdk-android/docs/html/navtreeindex1.js | 12 +- 12 files changed, 214 insertions(+), 134 deletions(-) diff --git a/polar-sdk-android/docs/html/BDBleApiImpl_8java_source.html b/polar-sdk-android/docs/html/BDBleApiImpl_8java_source.html index fdfaeb1f..aade49ad 100644 --- a/polar-sdk-android/docs/html/BDBleApiImpl_8java_source.html +++ b/polar-sdk-android/docs/html/BDBleApiImpl_8java_source.html @@ -66,44 +66,44 @@
BDBleApiImpl.java
-Go to the documentation of this file.
1 // Copyright © 2019 Polar Electro Oy. All rights reserved.
2 package polar.com.sdk.impl;
3 
4 import android.annotation.SuppressLint;
5 import android.bluetooth.le.ScanFilter;
6 import android.content.Context;
7 import android.os.Build;
8 import android.os.ParcelUuid;
9 import android.support.annotation.Nullable;
10 import android.util.Pair;
11 
12 import com.androidcommunications.polar.api.ble.BleDeviceListener;
13 import com.androidcommunications.polar.api.ble.BleLogger;
14 import com.androidcommunications.polar.api.ble.exceptions.BleDisconnected;
15 import com.androidcommunications.polar.api.ble.model.BleDeviceSession;
16 import com.androidcommunications.polar.api.ble.model.advertisement.BleAdvertisementContent;
17 import com.androidcommunications.polar.api.ble.model.advertisement.BlePolarHrAdvertisement;
18 import com.androidcommunications.polar.api.ble.model.gatt.BleGattBase;
19 import com.androidcommunications.polar.api.ble.model.gatt.client.BleBattClient;
20 import com.androidcommunications.polar.api.ble.model.gatt.client.BleDisClient;
21 import com.androidcommunications.polar.api.ble.model.gatt.client.BleHrClient;
22 import com.androidcommunications.polar.api.ble.model.gatt.client.BlePMDClient;
23 import com.androidcommunications.polar.api.ble.model.gatt.client.psftp.BlePsFtpClient;
24 import com.androidcommunications.polar.api.ble.model.gatt.client.psftp.BlePsFtpUtils;
25 import com.androidcommunications.polar.common.ble.BleUtils;
26 import com.androidcommunications.polar.enpoints.ble.bluedroid.host.BDDeviceListenerImpl;
27 
28 import org.reactivestreams.Publisher;
29 
30 import java.io.ByteArrayOutputStream;
31 import java.text.SimpleDateFormat;
32 import java.util.ArrayList;
33 import java.util.Calendar;
34 import java.util.Collections;
35 import java.util.Comparator;
36 import java.util.Date;
37 import java.util.HashMap;
38 import java.util.HashSet;
39 import java.util.List;
40 import java.util.Locale;
41 import java.util.Map;
42 import java.util.Set;
43 import java.util.UUID;
44 import java.util.concurrent.TimeUnit;
45 import java.util.concurrent.atomic.AtomicInteger;
46 
47 import fi.polar.remote.representation.protobuf.ExerciseSamples;
48 import fi.polar.remote.representation.protobuf.Types;
49 import io.reactivex.Completable;
50 import io.reactivex.CompletableEmitter;
51 import io.reactivex.CompletableOnSubscribe;
52 import io.reactivex.CompletableSource;
53 import io.reactivex.Flowable;
54 import io.reactivex.Scheduler;
55 import io.reactivex.Single;
56 import io.reactivex.SingleSource;
57 import io.reactivex.android.schedulers.AndroidSchedulers;
58 import io.reactivex.disposables.Disposable;
59 import io.reactivex.functions.Action;
60 import io.reactivex.functions.BiFunction;
61 import io.reactivex.functions.Consumer;
62 import io.reactivex.functions.Function;
63 import io.reactivex.functions.Predicate;
64 import io.reactivex.schedulers.Timed;
65 import polar.com.sdk.api.PolarBleApi;
84 import protocol.PftpRequest;
85 import protocol.PftpResponse;
86 
87 import static com.androidcommunications.polar.api.ble.model.BleDeviceSession.DeviceSessionState.SESSION_CLOSED;
88 import static com.androidcommunications.polar.api.ble.model.BleDeviceSession.DeviceSessionState.SESSION_OPEN;
89 import static com.androidcommunications.polar.api.ble.model.BleDeviceSession.DeviceSessionState.SESSION_OPENING;
90 
94 public class BDBleApiImpl extends PolarBleApi implements
95  BleDeviceListener.BleDeviceSessionStateChangedCallback,
96  BleDeviceListener.BlePowerStateChangedCallback {
97  protected final static String TAG = BDBleApiImpl.class.getSimpleName();
98  protected BleDeviceListener listener;
99  protected Map<String, Disposable> connectSubscriptions = new HashMap<>();
100  protected Scheduler scheduler;
103  protected static final int ANDROID_VERSION_O = 26;
104  BleDeviceListener.BleSearchPreFilter filter = new BleDeviceListener.BleSearchPreFilter() {
105  @Override
106  public boolean process(BleAdvertisementContent content) {
107  return content.getPolarDeviceId().length() != 0 && !content.getPolarDeviceType().equals("mobile");
108  }
109  };
110 
111  @SuppressLint({"NewApi", "CheckResult"})
112  public BDBleApiImpl(final Context context, int features) {
113  super(features);
114  Set<Class<? extends BleGattBase>> clients = new HashSet<>();
115  if ((this.features & PolarBleApi.FEATURE_HR) != 0) {
116  clients.add(BleHrClient.class);
117  }
118  if ((this.features & PolarBleApi.FEATURE_DEVICE_INFO) != 0) {
119  clients.add(BleDisClient.class);
120  }
121  if ((this.features & PolarBleApi.FEATURE_BATTERY_INFO) != 0) {
122  clients.add(BleBattClient.class);
123  }
124  if ((this.features & PolarBleApi.FEATURE_POLAR_SENSOR_STREAMING) != 0) {
125  clients.add(BlePMDClient.class);
126  }
127  if ((this.features & PolarBleApi.FEATURE_POLAR_FILE_TRANSFER) != 0) {
128  clients.add(BlePsFtpClient.class);
129  }
130  listener = new BDDeviceListenerImpl(context, clients);
131  listener.setScanPreFilter(filter);
132  listener.setDeviceSessionStateChangedCallback(this);
133  listener.setBlePowerStateCallback(this);
134  scheduler = AndroidSchedulers.from(context.getMainLooper());
135  BleLogger.setLoggerInterface(new BleLogger.BleLoggerInterface() {
136  @Override
137  public void d(String tag, String msg) {
138  log(tag + "/" + msg);
139  }
140 
141  @Override
142  public void e(String tag, String msg) {
143  logError(tag + "/" + msg);
144  }
145 
146  @Override
147  public void w(String tag, String msg) {
148  }
149 
150  @Override
151  public void i(String tag, String msg) {
152  }
153  });
154  }
155 
156  @SuppressLint("NewApi")
157  protected void enableAndroidScanFilter() {
158  if (Build.VERSION.SDK_INT >= ANDROID_VERSION_O) {
159  List<ScanFilter> filter = new ArrayList<>();
160  filter.add(new ScanFilter.Builder().setServiceUuid(
161  ParcelUuid.fromString(BleHrClient.HR_SERVICE.toString())).build());
162  filter.add(new ScanFilter.Builder().setServiceUuid(
163  ParcelUuid.fromString(BlePsFtpUtils.RFC77_PFTP_SERVICE.toString())).build());
164  listener.setScanFilters(filter);
165  }
166  }
167 
168  @Override
169  public void shutDown() {
170  listener.shutDown();
171  }
172 
173  @Override
174  public void cleanup() {
175  listener.removeAllSessions();
176  }
177 
178  @Override
179  public void setPolarFilter(boolean enable) {
180  if (!enable) {
181  listener.setScanPreFilter(null);
182  } else {
183  listener.setScanPreFilter(filter);
184  }
185  }
186 
187  @Override
188  public boolean isFeatureReady(final String deviceId, int feature) {
189  try {
190  switch (feature) {
192  return sessionPsFtpClientReady(deviceId) != null;
194  return sessionPmdClientReady(deviceId) != null;
195  }
196  } catch (Throwable ignored) {
197  }
198  return false;
199  }
200 
201  @Override
203  this.callback = callback;
205  }
206 
207  @Override
208  public void setApiLogger(@Nullable PolarBleApiLogger logger) {
209  this.logger = logger;
210  }
211 
212  @Override
213  public void setAutomaticReconnection(boolean disable) {
214  listener.setAutomaticReconnection(disable);
215  }
216 
217  @Override
218  public Completable setLocalTime(String identifier, Calendar cal) {
219  try {
220  final BleDeviceSession session = sessionPsFtpClientReady(identifier);
221  final BlePsFtpClient client = (BlePsFtpClient) session.fetchClient(BlePsFtpUtils.RFC77_PFTP_SERVICE);
222  PftpRequest.PbPFtpSetLocalTimeParams.Builder builder = PftpRequest.PbPFtpSetLocalTimeParams.newBuilder();
223  Types.PbDate date = Types.PbDate.newBuilder()
224  .setYear(cal.get(Calendar.YEAR))
225  .setMonth(cal.get(Calendar.MONTH) + 1)
226  .setDay(cal.get(Calendar.DAY_OF_MONTH)).build();
227  Types.PbTime time = Types.PbTime.newBuilder()
228  .setHour(cal.get(Calendar.HOUR_OF_DAY))
229  .setMinute(cal.get(Calendar.MINUTE))
230  .setSeconds(cal.get(Calendar.SECOND))
231  .setMillis(cal.get(Calendar.MILLISECOND)).build();
232  builder.setDate(date).setTime(time).setTzOffset((int) TimeUnit.MINUTES.convert(cal.get(Calendar.ZONE_OFFSET), TimeUnit.MILLISECONDS));
233  return client.query(PftpRequest.PbPFtpQuery.SET_LOCAL_TIME_VALUE, builder.build().toByteArray()).toObservable().ignoreElements();
234  } catch (Throwable error) {
235  return Completable.error(error);
236  }
237  }
238 
239  @Override
240  public Single<PolarSensorSetting> requestAccSettings(String identifier) {
241  return querySettings(identifier, BlePMDClient.PmdMeasurementType.ACC);
242  }
243 
244  @Override
245  public Single<PolarSensorSetting> requestEcgSettings(String identifier) {
246  return querySettings(identifier, BlePMDClient.PmdMeasurementType.ECG);
247  }
248 
249  @Override
250  public Single<PolarSensorSetting> requestPpgSettings(String identifier) {
251  return querySettings(identifier, BlePMDClient.PmdMeasurementType.PPG);
252  }
253 
254  @Override
255  public Single<PolarSensorSetting> requestBiozSettings(final String identifier) {
256  return querySettings(identifier, BlePMDClient.PmdMeasurementType.BIOZ);
257  }
258 
259  protected Single<PolarSensorSetting> querySettings(final String identifier, final BlePMDClient.PmdMeasurementType type) {
260  try {
261  final BleDeviceSession session = sessionPmdClientReady(identifier);
262  final BlePMDClient client = (BlePMDClient) session.fetchClient(BlePMDClient.PMD_SERVICE);
263  return client.querySettings(type).map(new Function<BlePMDClient.PmdSetting, PolarSensorSetting>() {
264  @Override
265  public PolarSensorSetting apply(BlePMDClient.PmdSetting setting) throws Exception {
266  return new PolarSensorSetting(setting.settings, type);
267  }
268  });
269  } catch (Throwable e) {
270  return Single.error(e);
271  }
272  }
273 
274  @Override
275  public void backgroundEntered() {
277  }
278 
279  @Override
280  public void foregroundEntered() {
281  listener.setScanFilters(null);
282  }
283 
284  @Override
285  public Completable autoConnectToDevice(final int rssiLimit, final String service, final int timeout, final TimeUnit unit, final String polarDeviceType) {
286  final long[] start = {0};
287  return Completable.create(new CompletableOnSubscribe() {
288  @Override
289  public void subscribe(CompletableEmitter emitter) throws Exception {
290  if (service == null || service.matches("([0-9a-fA-F]{4})")) {
291  emitter.onComplete();
292  } else {
293  emitter.tryOnError(new PolarInvalidArgument("Invalid service string format"));
294  }
295  }
296  }).andThen(listener.search(false).filter(new Predicate<BleDeviceSession>() {
297  @Override
298  public boolean test(BleDeviceSession bleDeviceSession) throws Exception {
299  if (bleDeviceSession.getMedianRssi() >= rssiLimit &&
300  bleDeviceSession.isConnectableAdvertisement() &&
301  (polarDeviceType == null || polarDeviceType.equals(bleDeviceSession.getPolarDeviceType())) &&
302  (service == null || bleDeviceSession.getAdvertisementContent().containsService(service))) {
303  if (start[0] == 0) {
304  start[0] = System.currentTimeMillis();
305  }
306  return true;
307  }
308  return false;
309  }
310  }).timestamp().takeUntil(new Predicate<Timed<BleDeviceSession>>() {
311  @Override
312  public boolean test(Timed<BleDeviceSession> bleDeviceSessionTimed) throws Exception {
313  long diff = bleDeviceSessionTimed.time(TimeUnit.MILLISECONDS) - start[0];
314  return (diff >= unit.toMillis(timeout));
315  }
316  }).reduce(new HashSet<BleDeviceSession>(), new BiFunction<Set<BleDeviceSession>, Timed<BleDeviceSession>, Set<BleDeviceSession>>() {
317  @Override
318  public Set<BleDeviceSession> apply(Set<BleDeviceSession> objects, Timed<BleDeviceSession> bleDeviceSessionTimed) throws Exception {
319  objects.add(bleDeviceSessionTimed.value());
320  return objects;
321  }
322  }).doOnSuccess(new Consumer<Set<BleDeviceSession>>() {
323  @Override
324  public void accept(Set<BleDeviceSession> set) throws Exception {
325  List<BleDeviceSession> list = new ArrayList<>(set);
326  Collections.sort(list, new Comparator<BleDeviceSession>() {
327  @Override
328  public int compare(BleDeviceSession o1, BleDeviceSession o2) {
329  return o1.getRssi() > o2.getRssi() ? -1 : 1;
330  }
331  });
332  listener.openSessionDirect(list.get(0));
333  log("auto connect search complete");
334  }
335  }).toObservable().ignoreElements());
336  }
337 
338  @Override
339  public Completable autoConnectToDevice(final int rssiLimit, final String service, final String polarDeviceType) {
340  return autoConnectToDevice(rssiLimit, service, 2, TimeUnit.SECONDS, polarDeviceType);
341  }
342 
343  @Override
344  public void connectToDevice(final String identifier) throws PolarInvalidArgument {
345  BleDeviceSession session = fetchSession(identifier);
346  if (session == null || session.getSessionState() == SESSION_CLOSED) {
347  if (connectSubscriptions.containsKey(identifier)) {
348  connectSubscriptions.get(identifier).dispose();
349  connectSubscriptions.remove(identifier);
350  }
351  if (session != null) {
352  listener.openSessionDirect(session);
353  } else {
354  connectSubscriptions.put(identifier, listener.search(false).filter(new Predicate<BleDeviceSession>() {
355  @Override
356  public boolean test(BleDeviceSession bleDeviceSession) throws Exception {
357  return identifier.contains(":") ?
358  bleDeviceSession.getAddress().equals(identifier) :
359  bleDeviceSession.getPolarDeviceId().equals(identifier);
360  }
361  }).take(1).observeOn(scheduler).subscribe(
362  new Consumer<BleDeviceSession>() {
363  @Override
364  public void accept(BleDeviceSession bleDeviceSession) throws Exception {
365  listener.openSessionDirect(bleDeviceSession);
366  }
367  },
368  new Consumer<Throwable>() {
369  @Override
370  public void accept(Throwable throwable) throws Exception {
371  logError(throwable.getMessage());
372  }
373  },
374  new Action() {
375  @Override
376  public void run() throws Exception {
377  log("connect search complete");
378  }
379  }
380  ));
381  }
382  }
383  }
384 
385  @Override
386  public void disconnectFromDevice(String identifier) throws PolarInvalidArgument {
387  BleDeviceSession session = fetchSession(identifier);
388  if (session != null) {
389  if (session.getSessionState() == SESSION_OPEN ||
390  session.getSessionState() == SESSION_OPENING ||
391  session.getSessionState() == BleDeviceSession.DeviceSessionState.SESSION_OPEN_PARK) {
392  listener.closeSessionDirect(session);
393  }
394  }
395  if (connectSubscriptions.containsKey(identifier)) {
396  connectSubscriptions.get(identifier).dispose();
397  connectSubscriptions.remove(identifier);
398  }
399  }
400 
401  @Override
402  public Completable startRecording(String identifier, String exerciseId, RecordingInterval interval, SampleType type) {
403  try {
404  final BleDeviceSession session = sessionPsFtpClientReady(identifier);
405  final BlePsFtpClient client = (BlePsFtpClient) session.fetchClient(BlePsFtpUtils.RFC77_PFTP_SERVICE);
406  if (session.getPolarDeviceType().equals("H10")) {
407  Types.PbSampleType t = type == SampleType.HR ?
408  Types.PbSampleType.SAMPLE_TYPE_HEART_RATE :
409  Types.PbSampleType.SAMPLE_TYPE_RR_INTERVAL;
410  Types.PbDuration duration = Types.PbDuration.newBuilder().setSeconds(interval.getValue()).build();
411  PftpRequest.PbPFtpRequestStartRecordingParams params = PftpRequest.PbPFtpRequestStartRecordingParams.newBuilder().
412  setSampleDataIdentifier(exerciseId).setSampleType(t).setRecordingInterval(duration).build();
413  return client.query(PftpRequest.PbPFtpQuery.REQUEST_START_RECORDING_VALUE, params.toByteArray()).toObservable().ignoreElements().onErrorResumeNext(new Function<Throwable, CompletableSource>() {
414  @Override
415  public CompletableSource apply(Throwable throwable) throws Exception {
416  return Completable.error(throwable);
417  }
418  });
419  }
420  return Completable.error(new PolarOperationNotSupported());
421  } catch (Throwable error) {
422  return Completable.error(error);
423  }
424  }
425 
426  @Override
427  public Completable stopRecording(String identifier) {
428  try {
429  final BleDeviceSession session = sessionPsFtpClientReady(identifier);
430  final BlePsFtpClient client = (BlePsFtpClient) session.fetchClient(BlePsFtpUtils.RFC77_PFTP_SERVICE);
431  if (session.getPolarDeviceType().equals("H10")) {
432  return client.query(PftpRequest.PbPFtpQuery.REQUEST_STOP_RECORDING_VALUE, null).toObservable().ignoreElements().onErrorResumeNext(new Function<Throwable, CompletableSource>() {
433  @Override
434  public CompletableSource apply(Throwable throwable) throws Exception {
435  return Completable.error(handleError(throwable));
436  }
437  });
438  }
439  return Completable.error(new PolarOperationNotSupported());
440  } catch (Throwable error) {
441  return Completable.error(error);
442  }
443  }
444 
445  @Override
446  public Single<Pair<Boolean, String>> requestRecordingStatus(String identifier) {
447  try {
448  final BleDeviceSession session = sessionPsFtpClientReady(identifier);
449  final BlePsFtpClient client = (BlePsFtpClient) session.fetchClient(BlePsFtpUtils.RFC77_PFTP_SERVICE);
450  if (session.getPolarDeviceType().equals("H10")) {
451  return client.query(PftpRequest.PbPFtpQuery.REQUEST_RECORDING_STATUS_VALUE, null).map(new Function<ByteArrayOutputStream, Pair<Boolean, String>>() {
452  @Override
453  public Pair<Boolean, String> apply(ByteArrayOutputStream byteArrayOutputStream) throws Exception {
454  PftpResponse.PbRequestRecordingStatusResult result = PftpResponse.PbRequestRecordingStatusResult.parseFrom(byteArrayOutputStream.toByteArray());
455  return new Pair<>(result.getRecordingOn(), result.hasSampleDataIdentifier() ? result.getSampleDataIdentifier() : "");
456  }
457  }).onErrorResumeNext(new Function<Throwable, SingleSource<? extends Pair<Boolean, String>>>() {
458  @Override
459  public SingleSource<? extends Pair<Boolean, String>> apply(Throwable throwable) throws Exception {
460  return Single.error(handleError(throwable));
461  }
462  });
463  }
464  return Single.error(new PolarOperationNotSupported());
465  } catch (Throwable error) {
466  return Single.error(error);
467  }
468  }
469 
470  @Override
471  public Flowable<PolarExerciseEntry> listExercises(String identifier) {
472  try {
473  final BleDeviceSession session = sessionPsFtpClientReady(identifier);
474  final BlePsFtpClient client = (BlePsFtpClient) session.fetchClient(BlePsFtpUtils.RFC77_PFTP_SERVICE);
475  switch (session.getPolarDeviceType()) {
476  case "OH1":
477  return fetchRecursively(client, "/U/0/", new FetchRecursiveCondition() {
478  @Override
479  public boolean include(String entry) {
480  return entry.matches("^([0-9]{8})(\\/)") ||
481  entry.matches("^([0-9]{6})(\\/)") ||
482  entry.equals("E/") ||
483  entry.equals("SAMPLES.BPB") ||
484  entry.equals("00/");
485  }
486  }).map(new Function<String, PolarExerciseEntry>() {
487  @Override
488  public PolarExerciseEntry apply(String p) throws Exception {
489  String[] components = p.split("/");
490  SimpleDateFormat format = new SimpleDateFormat("yyyyMMdd HHmmss", Locale.getDefault());
491  Date date = format.parse(components[3] + " " + components[5]);
492  return new PolarExerciseEntry(p, date, components[3] + components[5]);
493  }
494  }).onErrorResumeNext(new Function<Throwable, Publisher<? extends PolarExerciseEntry>>() {
495  @Override
496  public Publisher<? extends PolarExerciseEntry> apply(Throwable throwable) throws Exception {
497  return Flowable.error(handleError(throwable));
498  }
499  });
500  case "H10":
501  return fetchRecursively(client, "/", new FetchRecursiveCondition() {
502  @Override
503  public boolean include(String entry) {
504  return entry.endsWith("/") || entry.equals("SAMPLES.BPB");
505  }
506  }).map(new Function<String, PolarExerciseEntry>() {
507  @Override
508  public PolarExerciseEntry apply(String p) throws Exception {
509  String[] components = p.split("/");
510  return new PolarExerciseEntry(p, new Date(), components[1]);
511  }
512  }).onErrorResumeNext(new Function<Throwable, Publisher<? extends PolarExerciseEntry>>() {
513  @Override
514  public Publisher<? extends PolarExerciseEntry> apply(Throwable throwable) throws Exception {
515  return Flowable.error(handleError(throwable));
516  }
517  });
518  default:
519  return Flowable.error(new PolarOperationNotSupported());
520  }
521  } catch (Throwable error) {
522  return Flowable.error(error);
523  }
524  }
525 
526  @Override
527  public Single<PolarExerciseData> fetchExercise(String identifier, PolarExerciseEntry entry) {
528  try {
529  final BleDeviceSession session = sessionPsFtpClientReady(identifier);
530  final BlePsFtpClient client = (BlePsFtpClient) session.fetchClient(BlePsFtpUtils.RFC77_PFTP_SERVICE);
531  protocol.PftpRequest.PbPFtpOperation.Builder builder = protocol.PftpRequest.PbPFtpOperation.newBuilder();
532  builder.setCommand(PftpRequest.PbPFtpOperation.Command.GET);
533  builder.setPath(entry.path);
534  if (session.getPolarDeviceType().equals("OH1") || session.getPolarDeviceType().equals("H10")) {
535 
536  /*
537  TODO to improve throughput (device will request parameter update from mobile):
538 
539  Add these two notifications before reading ex
540  client.sendNotification(PftpNotification.PbPFtpHostToDevNotification.START_SYNC_VALUE, null).andThen(
541  client.sendNotification(PftpNotification.PbPFtpHostToDevNotification.INITIALIZE_SESSION_VALUE, null)
542  );
543 
544  Add these two notifications after reading ex
545  client.sendNotification(PftpNotification.PbPFtpHostToDevNotification.STOP_SYNC_VALUE,
546  PftpNotification.PbPFtpStopSyncParams.newBuilder().setCompleted(true).build().toByteArray()).andThen(
547  client.sendNotification(PftpNotification.PbPFtpHostToDevNotification.TERMINATE_SESSION_VALUE, null)
548  );
549  */
550 
551  return client.request(builder.build().toByteArray()).map(new Function<ByteArrayOutputStream, PolarExerciseData>() {
552  @Override
553  public PolarExerciseData apply(ByteArrayOutputStream byteArrayOutputStream) throws Exception {
554  ExerciseSamples.PbExerciseSamples samples = ExerciseSamples.PbExerciseSamples.parseFrom(byteArrayOutputStream.toByteArray());
555  if (samples.hasRrSamples()) {
556  return new PolarExerciseData(samples.getRecordingInterval().getSeconds(), samples.getRrSamples().getRrIntervalsList());
557  } else {
558  return new PolarExerciseData(samples.getRecordingInterval().getSeconds(), samples.getHeartRateSamplesList());
559  }
560  }
561  }).onErrorResumeNext(new Function<Throwable, SingleSource<? extends PolarExerciseData>>() {
562  @Override
563  public SingleSource<? extends PolarExerciseData> apply(Throwable throwable) throws Exception {
564  return Single.error(handleError(throwable));
565  }
566  });
567  }
568  return Single.error(new PolarOperationNotSupported());
569  } catch (Throwable error) {
570  return Single.error(error);
571  }
572  }
573 
574  @Override
575  public Completable removeExercise(String identifier, PolarExerciseEntry entry) {
576  try {
577  final BleDeviceSession session = sessionPsFtpClientReady(identifier);
578  final BlePsFtpClient client = (BlePsFtpClient) session.fetchClient(BlePsFtpUtils.RFC77_PFTP_SERVICE);
579  if (session.getPolarDeviceType().equals("OH1")) {
580  protocol.PftpRequest.PbPFtpOperation.Builder builder = protocol.PftpRequest.PbPFtpOperation.newBuilder();
581  builder.setCommand(PftpRequest.PbPFtpOperation.Command.GET);
582  final String[] components = entry.path.split("/");
583  final String exerciseParent = "/U/0/" + components[3] + "/E/";
584  builder.setPath(exerciseParent);
585  return client.request(builder.build().toByteArray()).flatMap(new Function<ByteArrayOutputStream, SingleSource<?>>() {
586  @Override
587  public SingleSource<?> apply(ByteArrayOutputStream byteArrayOutputStream) throws Exception {
588  PftpResponse.PbPFtpDirectory directory = PftpResponse.PbPFtpDirectory.parseFrom(byteArrayOutputStream.toByteArray());
589  protocol.PftpRequest.PbPFtpOperation.Builder removeBuilder = protocol.PftpRequest.PbPFtpOperation.newBuilder();
590  removeBuilder.setCommand(PftpRequest.PbPFtpOperation.Command.REMOVE);
591  if (directory.getEntriesCount() <= 1) {
592  // remove entire directory
593  removeBuilder.setPath("/U/0/" + components[3] + "/");
594  } else {
595  // remove only exercise
596  removeBuilder.setPath("/U/0/" + components[3] + "/E/" + components[5] + "/");
597  }
598  return client.request(removeBuilder.build().toByteArray());
599  }
600  }).toObservable().ignoreElements().onErrorResumeNext(new Function<Throwable, CompletableSource>() {
601  @Override
602  public CompletableSource apply(Throwable throwable) throws Exception {
603  return Completable.error(handleError(throwable));
604  }
605  });
606  } else if (session.getPolarDeviceType().equals("H10")) {
607  protocol.PftpRequest.PbPFtpOperation.Builder builder = protocol.PftpRequest.PbPFtpOperation.newBuilder();
608  builder.setCommand(PftpRequest.PbPFtpOperation.Command.REMOVE);
609  builder.setPath(entry.path);
610  return client.request(builder.build().toByteArray()).toObservable().ignoreElements().onErrorResumeNext(new Function<Throwable, CompletableSource>() {
611  @Override
612  public CompletableSource apply(Throwable throwable) throws Exception {
613  return Completable.error(handleError(throwable));
614  }
615  });
616  }
617  return Completable.error(new PolarOperationNotSupported());
618  } catch (Throwable error) {
619  return Completable.error(error);
620  }
621  }
622 
623  @Override
624  public Flowable<PolarDeviceInfo> searchForDevice() {
625  return listener.search(false).distinct().map(new Function<BleDeviceSession, PolarDeviceInfo>() {
626  @Override
627  public PolarDeviceInfo apply(BleDeviceSession bleDeviceSession) throws Exception {
628  return new PolarDeviceInfo(bleDeviceSession.getPolarDeviceId(),
629  bleDeviceSession.getAddress(),
630  bleDeviceSession.getRssi(),
631  bleDeviceSession.getName(),
632  bleDeviceSession.isConnectableAdvertisement());
633  }
634  });
635  }
636 
637  @Override
638  public Flowable<PolarHrBroadcastData> startListenForPolarHrBroadcasts(final Set<String> deviceIds) {
639  // set filter to null, NOTE this disables reconnection in background
640  return listener.search(false).filter(new Predicate<BleDeviceSession>() {
641  @Override
642  public boolean test(BleDeviceSession bleDeviceSession) throws Exception {
643  return (deviceIds == null || deviceIds.contains(bleDeviceSession.getPolarDeviceId())) &&
644  bleDeviceSession.getAdvertisementContent().getPolarHrAdvertisement().isPresent();
645  }
646  }).map(new Function<BleDeviceSession, PolarHrBroadcastData>() {
647  @Override
648  public PolarHrBroadcastData apply(BleDeviceSession bleDeviceSession) throws Exception {
649  BlePolarHrAdvertisement advertisement = bleDeviceSession.getBlePolarHrAdvertisement();
650  return new PolarHrBroadcastData(new PolarDeviceInfo(bleDeviceSession.getPolarDeviceId(),
651  bleDeviceSession.getAddress(),
652  bleDeviceSession.getRssi(),
653  bleDeviceSession.getName(),
654  bleDeviceSession.isConnectableAdvertisement()),
655  advertisement.getHrForDisplay(),
656  advertisement.getBatteryStatus() != 0);
657  }
658  });
659  }
660 
661  @Override
662  public Flowable<PolarEcgData> startEcgStreaming(String identifier,
663  PolarSensorSetting setting) {
664  try {
665  final BleDeviceSession session = sessionPmdClientReady(identifier);
666  final BlePMDClient client = (BlePMDClient) session.fetchClient(BlePMDClient.PMD_SERVICE);
667  return client.startMeasurement(BlePMDClient.PmdMeasurementType.ECG, setting.map2PmdSettings()).andThen(
668  client.monitorEcgNotifications(true).map(new Function<BlePMDClient.EcgData, PolarEcgData>() {
669  @Override
670  public PolarEcgData apply(BlePMDClient.EcgData ecgData) throws Exception {
671  List<Integer> samples = new ArrayList<>();
672  for (BlePMDClient.EcgData.EcgSample s : ecgData.ecgSamples) {
673  samples.add(s.microVolts);
674  }
675  return new PolarEcgData(samples, ecgData.timeStamp);
676  }
677  }).onErrorResumeNext(new Function<Throwable, Publisher<? extends PolarEcgData>>() {
678  @Override
679  public Publisher<? extends PolarEcgData> apply(Throwable throwable) throws Exception {
680  return Flowable.error(handleError(throwable));
681  }
682  }).doFinally(new Action() {
683  @Override
684  public void run() throws Exception {
685  stopPmdStreaming(session, client, BlePMDClient.PmdMeasurementType.ECG);
686  }
687  }));
688  } catch (Throwable t) {
689  return Flowable.error(t);
690  }
691  }
692 
693  @Override
694  public Flowable<PolarAccelerometerData> startAccStreaming(String identifier,
695  PolarSensorSetting setting) {
696  try {
697  final BleDeviceSession session = sessionPmdClientReady(identifier);
698  final BlePMDClient client = (BlePMDClient) session.fetchClient(BlePMDClient.PMD_SERVICE);
699  return client.startMeasurement(BlePMDClient.PmdMeasurementType.ACC, setting.map2PmdSettings()).andThen(
700  client.monitorAccNotifications(true).map(new Function<BlePMDClient.AccData, PolarAccelerometerData>() {
701  @Override
702  public PolarAccelerometerData apply(BlePMDClient.AccData accData) throws Exception {
703  List<PolarAccelerometerData.PolarAccelerometerSample> samples = new ArrayList<>();
704  for (BlePMDClient.AccData.AccSample s : accData.accSamples) {
705  samples.add(new PolarAccelerometerData.PolarAccelerometerSample(s.x, s.y, s.z));
706  }
707  return new PolarAccelerometerData(samples, accData.timeStamp);
708  }
709  }).onErrorResumeNext(new Function<Throwable, Publisher<? extends PolarAccelerometerData>>() {
710  @Override
711  public Publisher<? extends PolarAccelerometerData> apply(Throwable throwable) throws Exception {
712  return Flowable.error(handleError(throwable));
713  }
714  }).doFinally(new Action() {
715  @Override
716  public void run() throws Exception {
717  stopPmdStreaming(session, client, BlePMDClient.PmdMeasurementType.ACC);
718  }
719  }));
720  } catch (Throwable t) {
721  return Flowable.error(t);
722  }
723  }
724 
725  @Override
726  public Flowable<PolarOhrPPGData> startOhrPPGStreaming(String identifier,
727  PolarSensorSetting setting) {
728  try {
729  final BleDeviceSession session = sessionPmdClientReady(identifier);
730  final BlePMDClient client = (BlePMDClient) session.fetchClient(BlePMDClient.PMD_SERVICE);
731  return client.startMeasurement(BlePMDClient.PmdMeasurementType.PPG, setting.map2PmdSettings()).andThen(
732  client.monitorPpgNotifications(true).map(new Function<BlePMDClient.PpgData, PolarOhrPPGData>() {
733  @Override
734  public PolarOhrPPGData apply(BlePMDClient.PpgData ppgData) throws Exception {
735  List<PolarOhrPPGData.PolarOhrPPGSample> samples = new ArrayList<>();
736  for (BlePMDClient.PpgData.PpgSample s : ppgData.ppgSamples) {
737  samples.add(new PolarOhrPPGData.PolarOhrPPGSample(s.ppg0, s.ppg1, s.ppg2, s.ambient, s.ppgDataSamples, s.ambient1, s.status));
738  }
739  return new PolarOhrPPGData(samples, ppgData.timeStamp, ppgData.type);
740  }
741  }).doFinally(new Action() {
742  @Override
743  public void run() throws Exception {
744  stopPmdStreaming(session, client, BlePMDClient.PmdMeasurementType.PPG);
745  }
746  })).onErrorResumeNext(new Function<Throwable, Publisher<? extends PolarOhrPPGData>>() {
747  @Override
748  public Publisher<? extends PolarOhrPPGData> apply(Throwable throwable) throws Exception {
749  return Flowable.error(handleError(throwable));
750  }
751  });
752  } catch (Throwable t) {
753  return Flowable.error(t);
754  }
755  }
756 
757  @Override
758  public Flowable<PolarOhrPPIData> startOhrPPIStreaming(String identifier) {
759  try {
760  final BleDeviceSession session = sessionPmdClientReady(identifier);
761  final BlePMDClient client = (BlePMDClient) session.fetchClient(BlePMDClient.PMD_SERVICE);
762  return client.startMeasurement(BlePMDClient.PmdMeasurementType.PPI, new BlePMDClient.PmdSetting(new HashMap<BlePMDClient.PmdSetting.PmdSettingType, Integer>())).andThen(
763  client.monitorPpiNotifications(true).map(new Function<BlePMDClient.PpiData, PolarOhrPPIData>() {
764  @Override
765  public PolarOhrPPIData apply(BlePMDClient.PpiData ppiData) throws Exception {
766  List<PolarOhrPPIData.PolarOhrPPISample> samples = new ArrayList<>();
767  for (BlePMDClient.PpiData.PPSample ppSample : ppiData.ppSamples) {
768  samples.add(new PolarOhrPPIData.PolarOhrPPISample(ppSample.ppInMs,
769  ppSample.ppErrorEstimate,
770  ppSample.hr,
771  ppSample.blockerBit != 0,
772  ppSample.skinContactStatus != 0,
773  ppSample.skinContactSupported != 0));
774  }
775  return new PolarOhrPPIData(ppiData.timestamp, samples);
776  }
777  }).doFinally(new Action() {
778  @Override
779  public void run() throws Exception {
780  stopPmdStreaming(session, client, BlePMDClient.PmdMeasurementType.PPI);
781  }
782  })).onErrorResumeNext(new Function<Throwable, Publisher<? extends PolarOhrPPIData>>() {
783  @Override
784  public Publisher<? extends PolarOhrPPIData> apply(Throwable throwable) throws Exception {
785  return Flowable.error(handleError(throwable));
786  }
787  });
788  } catch (Throwable t) {
789  return Flowable.error(t);
790  }
791  }
792 
793  @Override
794  public Flowable<PolarBiozData> startBiozStreaming(final String identifier, PolarSensorSetting setting) {
795  try {
796  final BleDeviceSession session = sessionPmdClientReady(identifier);
797  final BlePMDClient client = (BlePMDClient) session.fetchClient(BlePMDClient.PMD_SERVICE);
798  return client.startMeasurement(BlePMDClient.PmdMeasurementType.BIOZ, setting.map2PmdSettings()).andThen(
799  client.monitorBiozNotifications(true).map(new Function<BlePMDClient.BiozData, PolarBiozData>() {
800  @Override
801  public PolarBiozData apply(BlePMDClient.BiozData biozData) throws Exception {
802  return new PolarBiozData(biozData.timeStamp, biozData.samples, biozData.status, biozData.type);
803  }
804  }).doFinally(new Action() {
805  @Override
806  public void run() throws Exception {
807  stopPmdStreaming(session, client, BlePMDClient.PmdMeasurementType.PPG);
808  }
809  })).onErrorResumeNext(new Function<Throwable, Publisher<? extends PolarBiozData>>() {
810  @Override
811  public Publisher<? extends PolarBiozData> apply(Throwable throwable) throws Exception {
812  return Flowable.error(handleError(throwable));
813  }
814  });
815  } catch (Throwable t) {
816  return Flowable.error(t);
817  }
818  }
819 
820  protected BleDeviceSession fetchSession(final String identifier) throws PolarInvalidArgument {
821  if (identifier.matches("^([0-9A-Fa-f]{2}[:-]){5}([0-9A-Fa-f]{2})$")) {
822  return sessionByAddress(identifier);
823  } else if (identifier.matches("([0-9a-fA-F]){6,8}")) {
824  return sessionByDeviceId(identifier);
825  }
826  throw new PolarInvalidArgument();
827  }
828 
829  protected BleDeviceSession sessionByAddress(final String address) throws PolarInvalidArgument {
830  for (BleDeviceSession session : listener.deviceSessions()) {
831  if (session.getAddress().equals(address)) {
832  return session;
833  }
834  }
835  return null;
836  }
837 
838  protected BleDeviceSession sessionByDeviceId(final String deviceId) throws PolarInvalidArgument {
839  for (BleDeviceSession session : listener.deviceSessions()) {
840  if (session.getAdvertisementContent().getPolarDeviceId().equals(deviceId)) {
841  return session;
842  }
843  }
844  return null;
845  }
846 
847  protected BleDeviceSession sessionServiceReady(final String identifier, UUID service) throws Throwable {
848  BleDeviceSession session = fetchSession(identifier);
849  if (session != null) {
850  if (session.getSessionState() == SESSION_OPEN) {
851  BleGattBase client = session.fetchClient(service);
852  if (client.isServiceDiscovered()) {
853  return session;
854  }
855  throw new PolarServiceNotAvailable();
856  }
857  throw new PolarDeviceDisconnected();
858  }
859  throw new PolarDeviceNotFound();
860  }
861 
862  public BleDeviceSession sessionPmdClientReady(final String identifier) throws Throwable {
863  BleDeviceSession session = sessionServiceReady(identifier, BlePMDClient.PMD_SERVICE);
864  BlePMDClient client = (BlePMDClient) session.fetchClient(BlePMDClient.PMD_SERVICE);
865  final AtomicInteger pair = client.getNotificationAtomicInteger(BlePMDClient.PMD_CP);
866  final AtomicInteger pairData = client.getNotificationAtomicInteger(BlePMDClient.PMD_DATA);
867  if (pair != null && pairData != null &&
868  pair.get() == BleGattBase.ATT_SUCCESS &&
869  pairData.get() == BleGattBase.ATT_SUCCESS) {
870  return session;
871  }
872  throw new PolarNotificationNotEnabled();
873  }
874 
875  protected BleDeviceSession sessionPsFtpClientReady(final String identifier) throws Throwable {
876  BleDeviceSession session = sessionServiceReady(identifier, BlePsFtpUtils.RFC77_PFTP_SERVICE);
877  BlePsFtpClient client = (BlePsFtpClient) session.fetchClient(BlePsFtpUtils.RFC77_PFTP_SERVICE);
878  final AtomicInteger pair = client.getNotificationAtomicInteger(BlePsFtpUtils.RFC77_PFTP_MTU_CHARACTERISTIC);
879  if (pair != null && pair.get() == BleGattBase.ATT_SUCCESS) {
880  return session;
881  }
882  throw new PolarNotificationNotEnabled();
883  }
884 
885  @SuppressLint("CheckResult")
886  protected void stopPmdStreaming(BleDeviceSession session, BlePMDClient client, BlePMDClient.PmdMeasurementType type) {
887  if (session.getSessionState() == SESSION_OPEN) {
888  // stop streaming
889  client.stopMeasurement(type).subscribe(
890  new Action() {
891  @Override
892  public void run() throws Exception {
893 
894  }
895  },
896  new Consumer<Throwable>() {
897  @Override
898  public void accept(Throwable throwable) throws Exception {
899  logError("failed to stop pmd stream: " + throwable.getLocalizedMessage());
900  }
901  }
902  );
903  }
904  }
905 
906  @SuppressLint("CheckResult")
907  protected void setupDevice(final BleDeviceSession session) {
908  final String deviceId = session.getPolarDeviceId().length() != 0 ? session.getPolarDeviceId() : session.getAddress();
909  session.monitorServicesDiscovered(true).observeOn(scheduler).toFlowable().flatMapIterable(
910  new Function<List<UUID>, Iterable<UUID>>() {
911  @Override
912  public Iterable<UUID> apply(List<UUID> uuids) throws Exception {
913  return uuids;
914  }
915  }
916  ).flatMap(new Function<UUID, Publisher<?>>() {
917  @Override
918  public Publisher<?> apply(UUID uuid) throws Exception {
919  if (session.fetchClient(uuid) != null) {
920  if (uuid.equals(BleHrClient.HR_SERVICE)) {
921  if (callback != null) {
922  callback.hrFeatureReady(deviceId);
923  }
924  final BleHrClient client = (BleHrClient) session.fetchClient(BleHrClient.HR_SERVICE);
925  client.observeHrNotifications(true).observeOn(scheduler).subscribe(
926  new Consumer<BleHrClient.HrNotificationData>() {
927  @Override
928  public void accept(BleHrClient.HrNotificationData hrNotificationData) throws Exception {
929  if (callback != null) {
931  new PolarHrData(hrNotificationData.hrValue,
932  hrNotificationData.rrs,
933  hrNotificationData.sensorContact,
934  hrNotificationData.sensorContactSupported,
935  hrNotificationData.rrPresent));
936  }
937  }
938  },
939  new Consumer<Throwable>() {
940  @Override
941  public void accept(Throwable throwable) throws Exception {
942  logError(throwable.getMessage());
943  }
944  },
945  new Action() {
946  @Override
947  public void run() throws Exception {
948 
949  }
950  }
951  );
952  } else if (uuid.equals(BleBattClient.BATTERY_SERVICE)) {
953  BleBattClient client = (BleBattClient) session.fetchClient(BleBattClient.BATTERY_SERVICE);
954  return client.waitBatteryLevelUpdate(true).observeOn(scheduler).doOnSuccess(new Consumer<Integer>() {
955  @Override
956  public void accept(Integer integer) throws Exception {
957  if (callback != null) {
958  callback.batteryLevelReceived(deviceId, integer);
959  }
960  }
961  }).toFlowable();
962  } else if (uuid.equals(BlePMDClient.PMD_SERVICE)) {
963  final BlePMDClient client = (BlePMDClient) session.fetchClient(BlePMDClient.PMD_SERVICE);
964  return client.waitNotificationEnabled(BlePMDClient.PMD_CP, true).
965  concatWith(client.waitNotificationEnabled(BlePMDClient.PMD_DATA, true)).andThen(client.readFeature(true).doOnSuccess(new Consumer<BlePMDClient.PmdFeature>() {
966  @Override
967  public void accept(BlePMDClient.PmdFeature pmdFeature) {
968  if (callback != null) {
969  if (pmdFeature.ecgSupported) {
970  callback.ecgFeatureReady(deviceId);
971  }
972  if (pmdFeature.accSupported) {
974  }
975  if (pmdFeature.ppgSupported) {
976  callback.ppgFeatureReady(deviceId);
977  }
978  if (pmdFeature.ppiSupported) {
979  callback.ppiFeatureReady(deviceId);
980  }
981  if (pmdFeature.bioZSupported) {
982  callback.biozFeatureReady(deviceId);
983  }
984  }
985  }
986  })).toFlowable();
987  } else if (uuid.equals(BleDisClient.DIS_SERVICE)) {
988  BleDisClient client = (BleDisClient) session.fetchClient(BleDisClient.DIS_SERVICE);
989  return client.observeDisInfo(true).observeOn(scheduler).doOnNext(new Consumer<Pair<UUID, String>>() {
990  @Override
991  public void accept(Pair<UUID, String> pair) {
992  if (callback != null) {
993  callback.disInformationReceived(deviceId, pair.first, pair.second);
994  }
995  }
996  });
997  } else if (uuid.equals(BlePsFtpUtils.RFC77_PFTP_SERVICE)) {
998  BlePsFtpClient client = (BlePsFtpClient) session.fetchClient(BlePsFtpUtils.RFC77_PFTP_SERVICE);
999  return client.waitPsFtpClientReady(true).observeOn(scheduler).doOnComplete(new Action() {
1000  @Override
1001  public void run() throws Exception {
1002  if (callback != null &&
1003  (session.getPolarDeviceType().equals("OH1") || session.getPolarDeviceType().equals("H10"))) {
1004  callback.polarFtpFeatureReady(deviceId);
1005  }
1006  }
1007  }).toFlowable();
1008  }
1009  }
1010  return Flowable.empty();
1011  }
1012  }).subscribe(
1013  new Consumer<Object>() {
1014  @Override
1015  public void accept(Object o) throws Exception {
1016 
1017  }
1018  },
1019  new Consumer<Throwable>() {
1020  @Override
1021  public void accept(Throwable throwable) throws Exception {
1022  logError(throwable.getMessage());
1023  }
1024  },
1025  new Action() {
1026  @Override
1027  public void run() throws Exception {
1028  log("complete");
1029  }
1030  });
1031  }
1032 
1033  protected Exception handleError(Throwable throwable) {
1034  if (throwable instanceof BleDisconnected) {
1035  return new PolarDeviceDisconnected();
1036  } else {
1037  return new Exception("Unknown Error: " + throwable.getLocalizedMessage());
1038  }
1039  }
1040 
1041  @Override
1042  public void stateChanged(BleDeviceSession session, BleDeviceSession.DeviceSessionState sessionState) {
1043  PolarDeviceInfo info = new PolarDeviceInfo(
1044  session.getPolarDeviceId().length() != 0 ?
1045  session.getPolarDeviceId() : session.getAddress(),
1046  session.getAddress(),
1047  session.getRssi(), session.getName(), true);
1048  switch (sessionState) {
1049  case SESSION_OPEN:
1050  if (callback != null) {
1051  callback.deviceConnected(info);
1052  }
1053  setupDevice(session);
1054  break;
1055  case SESSION_CLOSED:
1056  if (callback != null) {
1057  if (session.getPreviousState() == SESSION_OPEN ||
1058  session.getPreviousState() == BleDeviceSession.DeviceSessionState.SESSION_CLOSING) {
1060  }
1061  }
1062  break;
1063  case SESSION_OPENING:
1064  if (callback != null) {
1065  callback.deviceConnecting(info);
1066  }
1067  break;
1068  }
1069  }
1070 
1071  @Override
1072  public void stateChanged(Boolean power) {
1073  if (callback != null) {
1075  }
1076  }
1077 
1078  interface FetchRecursiveCondition {
1079  boolean include(String entry);
1080  }
1081 
1082  protected Flowable<String> fetchRecursively(final BlePsFtpClient client, final String path, final FetchRecursiveCondition condition) {
1083  protocol.PftpRequest.PbPFtpOperation.Builder builder = protocol.PftpRequest.PbPFtpOperation.newBuilder();
1084  builder.setCommand(PftpRequest.PbPFtpOperation.Command.GET);
1085  builder.setPath(path);
1086  return client.request(builder.build().toByteArray()).toFlowable().flatMap(new Function<ByteArrayOutputStream, Publisher<String>>() {
1087  @Override
1088  public Publisher<String> apply(ByteArrayOutputStream byteArrayOutputStream) throws Exception {
1089  PftpResponse.PbPFtpDirectory dir = PftpResponse.PbPFtpDirectory.parseFrom(byteArrayOutputStream.toByteArray());
1090  Set<String> entrys = new HashSet<>();
1091  for (int i = 0; i < dir.getEntriesCount(); ++i) {
1092  PftpResponse.PbPFtpEntry entry = dir.getEntries(i);
1093  if (condition.include(entry.getName())) {
1094  BleUtils.validate(entrys.add(path + entry.getName()), "duplicate entry");
1095  }
1096  }
1097  if (entrys.size() != 0) {
1098  return Flowable.fromIterable(entrys).flatMap(new Function<String, Publisher<String>>() {
1099  @Override
1100  public Publisher<String> apply(String s) {
1101  if (s.endsWith("/")) {
1102  return fetchRecursively(client, s, condition);
1103  } else {
1104  return Flowable.just(s);
1105  }
1106  }
1107  });
1108  }
1109  return Flowable.empty();
1110  }
1111  });
1112  }
1113 
1114  protected void log(final String message) {
1115  if (logger != null) {
1116  logger.message("" + message);
1117  }
1118  }
1119 
1120  protected void logError(final String message) {
1121  if (logger != null) {
1122  logger.message("Error: " + message);
1123  }
1124  }
1125 }
-
void log(final String message)
+Go to the documentation of this file.
1 // Copyright © 2019 Polar Electro Oy. All rights reserved.
2 package polar.com.sdk.impl;
3 
4 import android.annotation.SuppressLint;
5 import android.bluetooth.le.ScanFilter;
6 import android.content.Context;
7 import android.os.Build;
8 import android.os.ParcelUuid;
9 import android.support.annotation.Nullable;
10 import android.util.Pair;
11 
12 import com.androidcommunications.polar.api.ble.BleDeviceListener;
13 import com.androidcommunications.polar.api.ble.BleLogger;
14 import com.androidcommunications.polar.api.ble.exceptions.BleDisconnected;
15 import com.androidcommunications.polar.api.ble.model.BleDeviceSession;
16 import com.androidcommunications.polar.api.ble.model.advertisement.BleAdvertisementContent;
17 import com.androidcommunications.polar.api.ble.model.advertisement.BlePolarHrAdvertisement;
18 import com.androidcommunications.polar.api.ble.model.gatt.BleGattBase;
19 import com.androidcommunications.polar.api.ble.model.gatt.client.BleBattClient;
20 import com.androidcommunications.polar.api.ble.model.gatt.client.BleDisClient;
21 import com.androidcommunications.polar.api.ble.model.gatt.client.BleHrClient;
22 import com.androidcommunications.polar.api.ble.model.gatt.client.BlePMDClient;
23 import com.androidcommunications.polar.api.ble.model.gatt.client.psftp.BlePsFtpClient;
24 import com.androidcommunications.polar.api.ble.model.gatt.client.psftp.BlePsFtpUtils;
25 import com.androidcommunications.polar.common.ble.BleUtils;
26 import com.androidcommunications.polar.enpoints.ble.bluedroid.host.BDDeviceListenerImpl;
27 
28 import org.reactivestreams.Publisher;
29 
30 import java.io.ByteArrayOutputStream;
31 import java.text.SimpleDateFormat;
32 import java.util.ArrayList;
33 import java.util.Calendar;
34 import java.util.Collections;
35 import java.util.Comparator;
36 import java.util.Date;
37 import java.util.HashMap;
38 import java.util.HashSet;
39 import java.util.List;
40 import java.util.Locale;
41 import java.util.Map;
42 import java.util.Set;
43 import java.util.UUID;
44 import java.util.concurrent.TimeUnit;
45 import java.util.concurrent.atomic.AtomicInteger;
46 
47 import fi.polar.remote.representation.protobuf.ExerciseSamples;
48 import fi.polar.remote.representation.protobuf.Types;
49 import io.reactivex.Completable;
50 import io.reactivex.CompletableEmitter;
51 import io.reactivex.CompletableOnSubscribe;
52 import io.reactivex.CompletableSource;
53 import io.reactivex.Flowable;
54 import io.reactivex.Scheduler;
55 import io.reactivex.Single;
56 import io.reactivex.SingleSource;
57 import io.reactivex.android.schedulers.AndroidSchedulers;
58 import io.reactivex.disposables.Disposable;
59 import io.reactivex.functions.Action;
60 import io.reactivex.functions.BiFunction;
61 import io.reactivex.functions.Consumer;
62 import io.reactivex.functions.Function;
63 import io.reactivex.functions.Predicate;
64 import io.reactivex.schedulers.Timed;
65 import polar.com.sdk.api.PolarBleApi;
84 import protocol.PftpRequest;
85 import protocol.PftpResponse;
86 
87 import static com.androidcommunications.polar.api.ble.model.BleDeviceSession.DeviceSessionState.SESSION_CLOSED;
88 import static com.androidcommunications.polar.api.ble.model.BleDeviceSession.DeviceSessionState.SESSION_OPEN;
89 import static com.androidcommunications.polar.api.ble.model.BleDeviceSession.DeviceSessionState.SESSION_OPENING;
90 
94 public class BDBleApiImpl extends PolarBleApi implements
95  BleDeviceListener.BleDeviceSessionStateChangedCallback,
96  BleDeviceListener.BlePowerStateChangedCallback {
97  protected final static String TAG = BDBleApiImpl.class.getSimpleName();
98  protected BleDeviceListener listener;
99  protected Map<String, Disposable> connectSubscriptions = new HashMap<>();
100  protected Scheduler scheduler;
103  protected static final int ANDROID_VERSION_O = 26;
104  BleDeviceListener.BleSearchPreFilter filter = new BleDeviceListener.BleSearchPreFilter() {
105  @Override
106  public boolean process(BleAdvertisementContent content) {
107  return content.getPolarDeviceId().length() != 0 && !content.getPolarDeviceType().equals("mobile");
108  }
109  };
110 
111  @SuppressLint({"NewApi", "CheckResult"})
112  public BDBleApiImpl(final Context context, int features) {
113  super(features);
114  Set<Class<? extends BleGattBase>> clients = new HashSet<>();
115  if ((this.features & PolarBleApi.FEATURE_HR) != 0) {
116  clients.add(BleHrClient.class);
117  }
118  if ((this.features & PolarBleApi.FEATURE_DEVICE_INFO) != 0) {
119  clients.add(BleDisClient.class);
120  }
121  if ((this.features & PolarBleApi.FEATURE_BATTERY_INFO) != 0) {
122  clients.add(BleBattClient.class);
123  }
124  if ((this.features & PolarBleApi.FEATURE_POLAR_SENSOR_STREAMING) != 0) {
125  clients.add(BlePMDClient.class);
126  }
127  if ((this.features & PolarBleApi.FEATURE_POLAR_FILE_TRANSFER) != 0) {
128  clients.add(BlePsFtpClient.class);
129  }
130  listener = new BDDeviceListenerImpl(context, clients);
131  listener.setScanPreFilter(filter);
132  listener.setDeviceSessionStateChangedCallback(this);
133  listener.setBlePowerStateCallback(this);
134  scheduler = AndroidSchedulers.from(context.getMainLooper());
135  BleLogger.setLoggerInterface(new BleLogger.BleLoggerInterface() {
136  @Override
137  public void d(String tag, String msg) {
138  log(tag + "/" + msg);
139  }
140 
141  @Override
142  public void e(String tag, String msg) {
143  logError(tag + "/" + msg);
144  }
145 
146  @Override
147  public void w(String tag, String msg) {
148  }
149 
150  @Override
151  public void i(String tag, String msg) {
152  }
153  });
154  }
155 
156  @SuppressLint("NewApi")
157  protected void enableAndroidScanFilter() {
158  if (Build.VERSION.SDK_INT >= ANDROID_VERSION_O) {
159  List<ScanFilter> filter = new ArrayList<>();
160  filter.add(new ScanFilter.Builder().setServiceUuid(
161  ParcelUuid.fromString(BleHrClient.HR_SERVICE.toString())).build());
162  filter.add(new ScanFilter.Builder().setServiceUuid(
163  ParcelUuid.fromString(BlePsFtpUtils.RFC77_PFTP_SERVICE.toString())).build());
164  listener.setScanFilters(filter);
165  }
166  }
167 
168  @Override
169  public void setMtu(int mtu) {
170  listener.setMtu(mtu);
171  }
172 
173  @Override
174  public void shutDown() {
175  listener.shutDown();
176  }
177 
178  @Override
179  public void cleanup() {
180  listener.removeAllSessions();
181  }
182 
183  @Override
184  public void setPolarFilter(boolean enable) {
185  if (!enable) {
186  listener.setScanPreFilter(null);
187  } else {
188  listener.setScanPreFilter(filter);
189  }
190  }
191 
192  @Override
193  public boolean isFeatureReady(final String deviceId, int feature) {
194  try {
195  switch (feature) {
197  return sessionPsFtpClientReady(deviceId) != null;
199  return sessionPmdClientReady(deviceId) != null;
200  }
201  } catch (Throwable ignored) {
202  }
203  return false;
204  }
205 
206  @Override
208  this.callback = callback;
210  }
211 
212  @Override
213  public void setApiLogger(@Nullable PolarBleApiLogger logger) {
214  this.logger = logger;
215  }
216 
217  @Override
218  public void setAutomaticReconnection(boolean disable) {
219  listener.setAutomaticReconnection(disable);
220  }
221 
222  @Override
223  public Completable setLocalTime(String identifier, Calendar cal) {
224  try {
225  final BleDeviceSession session = sessionPsFtpClientReady(identifier);
226  final BlePsFtpClient client = (BlePsFtpClient) session.fetchClient(BlePsFtpUtils.RFC77_PFTP_SERVICE);
227  PftpRequest.PbPFtpSetLocalTimeParams.Builder builder = PftpRequest.PbPFtpSetLocalTimeParams.newBuilder();
228  Types.PbDate date = Types.PbDate.newBuilder()
229  .setYear(cal.get(Calendar.YEAR))
230  .setMonth(cal.get(Calendar.MONTH) + 1)
231  .setDay(cal.get(Calendar.DAY_OF_MONTH)).build();
232  Types.PbTime time = Types.PbTime.newBuilder()
233  .setHour(cal.get(Calendar.HOUR_OF_DAY))
234  .setMinute(cal.get(Calendar.MINUTE))
235  .setSeconds(cal.get(Calendar.SECOND))
236  .setMillis(cal.get(Calendar.MILLISECOND)).build();
237  builder.setDate(date).setTime(time).setTzOffset((int) TimeUnit.MINUTES.convert(cal.get(Calendar.ZONE_OFFSET), TimeUnit.MILLISECONDS));
238  return client.query(PftpRequest.PbPFtpQuery.SET_LOCAL_TIME_VALUE, builder.build().toByteArray()).toObservable().ignoreElements();
239  } catch (Throwable error) {
240  return Completable.error(error);
241  }
242  }
243 
244  @Override
245  public Single<PolarSensorSetting> requestAccSettings(String identifier) {
246  return querySettings(identifier, BlePMDClient.PmdMeasurementType.ACC);
247  }
248 
249  @Override
250  public Single<PolarSensorSetting> requestEcgSettings(String identifier) {
251  return querySettings(identifier, BlePMDClient.PmdMeasurementType.ECG);
252  }
253 
254  @Override
255  public Single<PolarSensorSetting> requestPpgSettings(String identifier) {
256  return querySettings(identifier, BlePMDClient.PmdMeasurementType.PPG);
257  }
258 
259  @Override
260  public Single<PolarSensorSetting> requestBiozSettings(final String identifier) {
261  return querySettings(identifier, BlePMDClient.PmdMeasurementType.BIOZ);
262  }
263 
264  protected Single<PolarSensorSetting> querySettings(final String identifier, final BlePMDClient.PmdMeasurementType type) {
265  try {
266  final BleDeviceSession session = sessionPmdClientReady(identifier);
267  final BlePMDClient client = (BlePMDClient) session.fetchClient(BlePMDClient.PMD_SERVICE);
268  return client.querySettings(type).map(new Function<BlePMDClient.PmdSetting, PolarSensorSetting>() {
269  @Override
270  public PolarSensorSetting apply(BlePMDClient.PmdSetting setting) throws Exception {
271  return new PolarSensorSetting(setting.settings, type);
272  }
273  });
274  } catch (Throwable e) {
275  return Single.error(e);
276  }
277  }
278 
279  @Override
280  public void backgroundEntered() {
282  }
283 
284  @Override
285  public void foregroundEntered() {
286  listener.setScanFilters(null);
287  }
288 
289  @Override
290  public Completable autoConnectToDevice(final int rssiLimit, final String service, final int timeout, final TimeUnit unit, final String polarDeviceType) {
291  final long[] start = {0};
292  return Completable.create(new CompletableOnSubscribe() {
293  @Override
294  public void subscribe(CompletableEmitter emitter) throws Exception {
295  if (service == null || service.matches("([0-9a-fA-F]{4})")) {
296  emitter.onComplete();
297  } else {
298  emitter.tryOnError(new PolarInvalidArgument("Invalid service string format"));
299  }
300  }
301  }).andThen(listener.search(false).filter(new Predicate<BleDeviceSession>() {
302  @Override
303  public boolean test(BleDeviceSession bleDeviceSession) throws Exception {
304  if (bleDeviceSession.getMedianRssi() >= rssiLimit &&
305  bleDeviceSession.isConnectableAdvertisement() &&
306  (polarDeviceType == null || polarDeviceType.equals(bleDeviceSession.getPolarDeviceType())) &&
307  (service == null || bleDeviceSession.getAdvertisementContent().containsService(service))) {
308  if (start[0] == 0) {
309  start[0] = System.currentTimeMillis();
310  }
311  return true;
312  }
313  return false;
314  }
315  }).timestamp().takeUntil(new Predicate<Timed<BleDeviceSession>>() {
316  @Override
317  public boolean test(Timed<BleDeviceSession> bleDeviceSessionTimed) throws Exception {
318  long diff = bleDeviceSessionTimed.time(TimeUnit.MILLISECONDS) - start[0];
319  return (diff >= unit.toMillis(timeout));
320  }
321  }).reduce(new HashSet<BleDeviceSession>(), new BiFunction<Set<BleDeviceSession>, Timed<BleDeviceSession>, Set<BleDeviceSession>>() {
322  @Override
323  public Set<BleDeviceSession> apply(Set<BleDeviceSession> objects, Timed<BleDeviceSession> bleDeviceSessionTimed) throws Exception {
324  objects.add(bleDeviceSessionTimed.value());
325  return objects;
326  }
327  }).doOnSuccess(new Consumer<Set<BleDeviceSession>>() {
328  @Override
329  public void accept(Set<BleDeviceSession> set) throws Exception {
330  List<BleDeviceSession> list = new ArrayList<>(set);
331  Collections.sort(list, new Comparator<BleDeviceSession>() {
332  @Override
333  public int compare(BleDeviceSession o1, BleDeviceSession o2) {
334  return o1.getRssi() > o2.getRssi() ? -1 : 1;
335  }
336  });
337  listener.openSessionDirect(list.get(0));
338  log("auto connect search complete");
339  }
340  }).toObservable().ignoreElements());
341  }
342 
343  @Override
344  public Completable autoConnectToDevice(final int rssiLimit, final String service, final String polarDeviceType) {
345  return autoConnectToDevice(rssiLimit, service, 2, TimeUnit.SECONDS, polarDeviceType);
346  }
347 
348  @Override
349  public void connectToDevice(final String identifier) throws PolarInvalidArgument {
350  BleDeviceSession session = fetchSession(identifier);
351  if (session == null || session.getSessionState() == SESSION_CLOSED) {
352  if (connectSubscriptions.containsKey(identifier)) {
353  connectSubscriptions.get(identifier).dispose();
354  connectSubscriptions.remove(identifier);
355  }
356  if (session != null) {
357  listener.openSessionDirect(session);
358  } else {
359  connectSubscriptions.put(identifier, listener.search(false).filter(new Predicate<BleDeviceSession>() {
360  @Override
361  public boolean test(BleDeviceSession bleDeviceSession) throws Exception {
362  return identifier.contains(":") ?
363  bleDeviceSession.getAddress().equals(identifier) :
364  bleDeviceSession.getPolarDeviceId().equals(identifier);
365  }
366  }).take(1).observeOn(scheduler).subscribe(
367  new Consumer<BleDeviceSession>() {
368  @Override
369  public void accept(BleDeviceSession bleDeviceSession) throws Exception {
370  listener.openSessionDirect(bleDeviceSession);
371  }
372  },
373  new Consumer<Throwable>() {
374  @Override
375  public void accept(Throwable throwable) throws Exception {
376  logError(throwable.getMessage());
377  }
378  },
379  new Action() {
380  @Override
381  public void run() throws Exception {
382  log("connect search complete");
383  }
384  }
385  ));
386  }
387  }
388  }
389 
390  @Override
391  public void disconnectFromDevice(String identifier) throws PolarInvalidArgument {
392  BleDeviceSession session = fetchSession(identifier);
393  if (session != null) {
394  if (session.getSessionState() == SESSION_OPEN ||
395  session.getSessionState() == SESSION_OPENING ||
396  session.getSessionState() == BleDeviceSession.DeviceSessionState.SESSION_OPEN_PARK) {
397  listener.closeSessionDirect(session);
398  }
399  }
400  if (connectSubscriptions.containsKey(identifier)) {
401  connectSubscriptions.get(identifier).dispose();
402  connectSubscriptions.remove(identifier);
403  }
404  }
405 
406  @Override
407  public Completable startRecording(String identifier, String exerciseId, RecordingInterval interval, SampleType type) {
408  try {
409  final BleDeviceSession session = sessionPsFtpClientReady(identifier);
410  final BlePsFtpClient client = (BlePsFtpClient) session.fetchClient(BlePsFtpUtils.RFC77_PFTP_SERVICE);
411  if (session.getPolarDeviceType().equals("H10")) {
412  Types.PbSampleType t = type == SampleType.HR ?
413  Types.PbSampleType.SAMPLE_TYPE_HEART_RATE :
414  Types.PbSampleType.SAMPLE_TYPE_RR_INTERVAL;
415  Types.PbDuration duration = Types.PbDuration.newBuilder().setSeconds(interval.getValue()).build();
416  PftpRequest.PbPFtpRequestStartRecordingParams params = PftpRequest.PbPFtpRequestStartRecordingParams.newBuilder().
417  setSampleDataIdentifier(exerciseId).setSampleType(t).setRecordingInterval(duration).build();
418  return client.query(PftpRequest.PbPFtpQuery.REQUEST_START_RECORDING_VALUE, params.toByteArray()).toObservable().ignoreElements().onErrorResumeNext(new Function<Throwable, CompletableSource>() {
419  @Override
420  public CompletableSource apply(Throwable throwable) throws Exception {
421  return Completable.error(throwable);
422  }
423  });
424  }
425  return Completable.error(new PolarOperationNotSupported());
426  } catch (Throwable error) {
427  return Completable.error(error);
428  }
429  }
430 
431  @Override
432  public Completable stopRecording(String identifier) {
433  try {
434  final BleDeviceSession session = sessionPsFtpClientReady(identifier);
435  final BlePsFtpClient client = (BlePsFtpClient) session.fetchClient(BlePsFtpUtils.RFC77_PFTP_SERVICE);
436  if (session.getPolarDeviceType().equals("H10")) {
437  return client.query(PftpRequest.PbPFtpQuery.REQUEST_STOP_RECORDING_VALUE, null).toObservable().ignoreElements().onErrorResumeNext(new Function<Throwable, CompletableSource>() {
438  @Override
439  public CompletableSource apply(Throwable throwable) throws Exception {
440  return Completable.error(handleError(throwable));
441  }
442  });
443  }
444  return Completable.error(new PolarOperationNotSupported());
445  } catch (Throwable error) {
446  return Completable.error(error);
447  }
448  }
449 
450  @Override
451  public Single<Pair<Boolean, String>> requestRecordingStatus(String identifier) {
452  try {
453  final BleDeviceSession session = sessionPsFtpClientReady(identifier);
454  final BlePsFtpClient client = (BlePsFtpClient) session.fetchClient(BlePsFtpUtils.RFC77_PFTP_SERVICE);
455  if (session.getPolarDeviceType().equals("H10")) {
456  return client.query(PftpRequest.PbPFtpQuery.REQUEST_RECORDING_STATUS_VALUE, null).map(new Function<ByteArrayOutputStream, Pair<Boolean, String>>() {
457  @Override
458  public Pair<Boolean, String> apply(ByteArrayOutputStream byteArrayOutputStream) throws Exception {
459  PftpResponse.PbRequestRecordingStatusResult result = PftpResponse.PbRequestRecordingStatusResult.parseFrom(byteArrayOutputStream.toByteArray());
460  return new Pair<>(result.getRecordingOn(), result.hasSampleDataIdentifier() ? result.getSampleDataIdentifier() : "");
461  }
462  }).onErrorResumeNext(new Function<Throwable, SingleSource<? extends Pair<Boolean, String>>>() {
463  @Override
464  public SingleSource<? extends Pair<Boolean, String>> apply(Throwable throwable) throws Exception {
465  return Single.error(handleError(throwable));
466  }
467  });
468  }
469  return Single.error(new PolarOperationNotSupported());
470  } catch (Throwable error) {
471  return Single.error(error);
472  }
473  }
474 
475  @Override
476  public Flowable<PolarExerciseEntry> listExercises(String identifier) {
477  try {
478  final BleDeviceSession session = sessionPsFtpClientReady(identifier);
479  final BlePsFtpClient client = (BlePsFtpClient) session.fetchClient(BlePsFtpUtils.RFC77_PFTP_SERVICE);
480  switch (session.getPolarDeviceType()) {
481  case "OH1":
482  return fetchRecursively(client, "/U/0/", new FetchRecursiveCondition() {
483  @Override
484  public boolean include(String entry) {
485  return entry.matches("^([0-9]{8})(\\/)") ||
486  entry.matches("^([0-9]{6})(\\/)") ||
487  entry.equals("E/") ||
488  entry.equals("SAMPLES.BPB") ||
489  entry.equals("00/");
490  }
491  }).map(new Function<String, PolarExerciseEntry>() {
492  @Override
493  public PolarExerciseEntry apply(String p) throws Exception {
494  String[] components = p.split("/");
495  SimpleDateFormat format = new SimpleDateFormat("yyyyMMdd HHmmss", Locale.getDefault());
496  Date date = format.parse(components[3] + " " + components[5]);
497  return new PolarExerciseEntry(p, date, components[3] + components[5]);
498  }
499  }).onErrorResumeNext(new Function<Throwable, Publisher<? extends PolarExerciseEntry>>() {
500  @Override
501  public Publisher<? extends PolarExerciseEntry> apply(Throwable throwable) throws Exception {
502  return Flowable.error(handleError(throwable));
503  }
504  });
505  case "H10":
506  return fetchRecursively(client, "/", new FetchRecursiveCondition() {
507  @Override
508  public boolean include(String entry) {
509  return entry.endsWith("/") || entry.equals("SAMPLES.BPB");
510  }
511  }).map(new Function<String, PolarExerciseEntry>() {
512  @Override
513  public PolarExerciseEntry apply(String p) throws Exception {
514  String[] components = p.split("/");
515  return new PolarExerciseEntry(p, new Date(), components[1]);
516  }
517  }).onErrorResumeNext(new Function<Throwable, Publisher<? extends PolarExerciseEntry>>() {
518  @Override
519  public Publisher<? extends PolarExerciseEntry> apply(Throwable throwable) throws Exception {
520  return Flowable.error(handleError(throwable));
521  }
522  });
523  default:
524  return Flowable.error(new PolarOperationNotSupported());
525  }
526  } catch (Throwable error) {
527  return Flowable.error(error);
528  }
529  }
530 
531  @Override
532  public Single<PolarExerciseData> fetchExercise(String identifier, PolarExerciseEntry entry) {
533  try {
534  final BleDeviceSession session = sessionPsFtpClientReady(identifier);
535  final BlePsFtpClient client = (BlePsFtpClient) session.fetchClient(BlePsFtpUtils.RFC77_PFTP_SERVICE);
536  protocol.PftpRequest.PbPFtpOperation.Builder builder = protocol.PftpRequest.PbPFtpOperation.newBuilder();
537  builder.setCommand(PftpRequest.PbPFtpOperation.Command.GET);
538  builder.setPath(entry.path);
539  if (session.getPolarDeviceType().equals("OH1") || session.getPolarDeviceType().equals("H10")) {
540 
541  /*
542  TODO to improve throughput (device will request parameter update from mobile):
543 
544  Add these two notifications before reading ex
545  client.sendNotification(PftpNotification.PbPFtpHostToDevNotification.START_SYNC_VALUE, null).andThen(
546  client.sendNotification(PftpNotification.PbPFtpHostToDevNotification.INITIALIZE_SESSION_VALUE, null)
547  );
548 
549  Add these two notifications after reading ex
550  client.sendNotification(PftpNotification.PbPFtpHostToDevNotification.STOP_SYNC_VALUE,
551  PftpNotification.PbPFtpStopSyncParams.newBuilder().setCompleted(true).build().toByteArray()).andThen(
552  client.sendNotification(PftpNotification.PbPFtpHostToDevNotification.TERMINATE_SESSION_VALUE, null)
553  );
554  */
555 
556  return client.request(builder.build().toByteArray()).map(new Function<ByteArrayOutputStream, PolarExerciseData>() {
557  @Override
558  public PolarExerciseData apply(ByteArrayOutputStream byteArrayOutputStream) throws Exception {
559  ExerciseSamples.PbExerciseSamples samples = ExerciseSamples.PbExerciseSamples.parseFrom(byteArrayOutputStream.toByteArray());
560  if (samples.hasRrSamples()) {
561  return new PolarExerciseData(samples.getRecordingInterval().getSeconds(), samples.getRrSamples().getRrIntervalsList());
562  } else {
563  return new PolarExerciseData(samples.getRecordingInterval().getSeconds(), samples.getHeartRateSamplesList());
564  }
565  }
566  }).onErrorResumeNext(new Function<Throwable, SingleSource<? extends PolarExerciseData>>() {
567  @Override
568  public SingleSource<? extends PolarExerciseData> apply(Throwable throwable) throws Exception {
569  return Single.error(handleError(throwable));
570  }
571  });
572  }
573  return Single.error(new PolarOperationNotSupported());
574  } catch (Throwable error) {
575  return Single.error(error);
576  }
577  }
578 
579  @Override
580  public Completable removeExercise(String identifier, PolarExerciseEntry entry) {
581  try {
582  final BleDeviceSession session = sessionPsFtpClientReady(identifier);
583  final BlePsFtpClient client = (BlePsFtpClient) session.fetchClient(BlePsFtpUtils.RFC77_PFTP_SERVICE);
584  if (session.getPolarDeviceType().equals("OH1")) {
585  protocol.PftpRequest.PbPFtpOperation.Builder builder = protocol.PftpRequest.PbPFtpOperation.newBuilder();
586  builder.setCommand(PftpRequest.PbPFtpOperation.Command.GET);
587  final String[] components = entry.path.split("/");
588  final String exerciseParent = "/U/0/" + components[3] + "/E/";
589  builder.setPath(exerciseParent);
590  return client.request(builder.build().toByteArray()).flatMap(new Function<ByteArrayOutputStream, SingleSource<?>>() {
591  @Override
592  public SingleSource<?> apply(ByteArrayOutputStream byteArrayOutputStream) throws Exception {
593  PftpResponse.PbPFtpDirectory directory = PftpResponse.PbPFtpDirectory.parseFrom(byteArrayOutputStream.toByteArray());
594  protocol.PftpRequest.PbPFtpOperation.Builder removeBuilder = protocol.PftpRequest.PbPFtpOperation.newBuilder();
595  removeBuilder.setCommand(PftpRequest.PbPFtpOperation.Command.REMOVE);
596  if (directory.getEntriesCount() <= 1) {
597  // remove entire directory
598  removeBuilder.setPath("/U/0/" + components[3] + "/");
599  } else {
600  // remove only exercise
601  removeBuilder.setPath("/U/0/" + components[3] + "/E/" + components[5] + "/");
602  }
603  return client.request(removeBuilder.build().toByteArray());
604  }
605  }).toObservable().ignoreElements().onErrorResumeNext(new Function<Throwable, CompletableSource>() {
606  @Override
607  public CompletableSource apply(Throwable throwable) throws Exception {
608  return Completable.error(handleError(throwable));
609  }
610  });
611  } else if (session.getPolarDeviceType().equals("H10")) {
612  protocol.PftpRequest.PbPFtpOperation.Builder builder = protocol.PftpRequest.PbPFtpOperation.newBuilder();
613  builder.setCommand(PftpRequest.PbPFtpOperation.Command.REMOVE);
614  builder.setPath(entry.path);
615  return client.request(builder.build().toByteArray()).toObservable().ignoreElements().onErrorResumeNext(new Function<Throwable, CompletableSource>() {
616  @Override
617  public CompletableSource apply(Throwable throwable) throws Exception {
618  return Completable.error(handleError(throwable));
619  }
620  });
621  }
622  return Completable.error(new PolarOperationNotSupported());
623  } catch (Throwable error) {
624  return Completable.error(error);
625  }
626  }
627 
628  @Override
629  public Flowable<PolarDeviceInfo> searchForDevice() {
630  return listener.search(false).distinct().map(new Function<BleDeviceSession, PolarDeviceInfo>() {
631  @Override
632  public PolarDeviceInfo apply(BleDeviceSession bleDeviceSession) throws Exception {
633  return new PolarDeviceInfo(bleDeviceSession.getPolarDeviceId(),
634  bleDeviceSession.getAddress(),
635  bleDeviceSession.getRssi(),
636  bleDeviceSession.getName(),
637  bleDeviceSession.isConnectableAdvertisement());
638  }
639  });
640  }
641 
642  @Override
643  public Flowable<PolarHrBroadcastData> startListenForPolarHrBroadcasts(final Set<String> deviceIds) {
644  // set filter to null, NOTE this disables reconnection in background
645  return listener.search(false).filter(new Predicate<BleDeviceSession>() {
646  @Override
647  public boolean test(BleDeviceSession bleDeviceSession) throws Exception {
648  return (deviceIds == null || deviceIds.contains(bleDeviceSession.getPolarDeviceId())) &&
649  bleDeviceSession.getAdvertisementContent().getPolarHrAdvertisement().isPresent();
650  }
651  }).map(new Function<BleDeviceSession, PolarHrBroadcastData>() {
652  @Override
653  public PolarHrBroadcastData apply(BleDeviceSession bleDeviceSession) throws Exception {
654  BlePolarHrAdvertisement advertisement = bleDeviceSession.getBlePolarHrAdvertisement();
655  return new PolarHrBroadcastData(new PolarDeviceInfo(bleDeviceSession.getPolarDeviceId(),
656  bleDeviceSession.getAddress(),
657  bleDeviceSession.getRssi(),
658  bleDeviceSession.getName(),
659  bleDeviceSession.isConnectableAdvertisement()),
660  advertisement.getHrForDisplay(),
661  advertisement.getBatteryStatus() != 0);
662  }
663  });
664  }
665 
666  @Override
667  public Flowable<PolarEcgData> startEcgStreaming(String identifier,
668  PolarSensorSetting setting) {
669  try {
670  final BleDeviceSession session = sessionPmdClientReady(identifier);
671  final BlePMDClient client = (BlePMDClient) session.fetchClient(BlePMDClient.PMD_SERVICE);
672  return client.startMeasurement(BlePMDClient.PmdMeasurementType.ECG, setting.map2PmdSettings()).andThen(
673  client.monitorEcgNotifications(true).map(new Function<BlePMDClient.EcgData, PolarEcgData>() {
674  @Override
675  public PolarEcgData apply(BlePMDClient.EcgData ecgData) throws Exception {
676  List<Integer> samples = new ArrayList<>();
677  for (BlePMDClient.EcgData.EcgSample s : ecgData.ecgSamples) {
678  samples.add(s.microVolts);
679  }
680  return new PolarEcgData(samples, ecgData.timeStamp);
681  }
682  }).onErrorResumeNext(new Function<Throwable, Publisher<? extends PolarEcgData>>() {
683  @Override
684  public Publisher<? extends PolarEcgData> apply(Throwable throwable) throws Exception {
685  return Flowable.error(handleError(throwable));
686  }
687  }).doFinally(new Action() {
688  @Override
689  public void run() throws Exception {
690  stopPmdStreaming(session, client, BlePMDClient.PmdMeasurementType.ECG);
691  }
692  }));
693  } catch (Throwable t) {
694  return Flowable.error(t);
695  }
696  }
697 
698  @Override
699  public Flowable<PolarAccelerometerData> startAccStreaming(String identifier,
700  PolarSensorSetting setting) {
701  try {
702  final BleDeviceSession session = sessionPmdClientReady(identifier);
703  final BlePMDClient client = (BlePMDClient) session.fetchClient(BlePMDClient.PMD_SERVICE);
704  return client.startMeasurement(BlePMDClient.PmdMeasurementType.ACC, setting.map2PmdSettings()).andThen(
705  client.monitorAccNotifications(true).map(new Function<BlePMDClient.AccData, PolarAccelerometerData>() {
706  @Override
707  public PolarAccelerometerData apply(BlePMDClient.AccData accData) throws Exception {
708  List<PolarAccelerometerData.PolarAccelerometerSample> samples = new ArrayList<>();
709  for (BlePMDClient.AccData.AccSample s : accData.accSamples) {
710  samples.add(new PolarAccelerometerData.PolarAccelerometerSample(s.x, s.y, s.z));
711  }
712  return new PolarAccelerometerData(samples, accData.timeStamp);
713  }
714  }).onErrorResumeNext(new Function<Throwable, Publisher<? extends PolarAccelerometerData>>() {
715  @Override
716  public Publisher<? extends PolarAccelerometerData> apply(Throwable throwable) throws Exception {
717  return Flowable.error(handleError(throwable));
718  }
719  }).doFinally(new Action() {
720  @Override
721  public void run() throws Exception {
722  stopPmdStreaming(session, client, BlePMDClient.PmdMeasurementType.ACC);
723  }
724  }));
725  } catch (Throwable t) {
726  return Flowable.error(t);
727  }
728  }
729 
730  @Override
731  public Flowable<PolarOhrPPGData> startOhrPPGStreaming(String identifier,
732  PolarSensorSetting setting) {
733  try {
734  final BleDeviceSession session = sessionPmdClientReady(identifier);
735  final BlePMDClient client = (BlePMDClient) session.fetchClient(BlePMDClient.PMD_SERVICE);
736  return client.startMeasurement(BlePMDClient.PmdMeasurementType.PPG, setting.map2PmdSettings()).andThen(
737  client.monitorPpgNotifications(true).map(new Function<BlePMDClient.PpgData, PolarOhrPPGData>() {
738  @Override
739  public PolarOhrPPGData apply(BlePMDClient.PpgData ppgData) throws Exception {
740  List<PolarOhrPPGData.PolarOhrPPGSample> samples = new ArrayList<>();
741  for (BlePMDClient.PpgData.PpgSample s : ppgData.ppgSamples) {
742  samples.add(new PolarOhrPPGData.PolarOhrPPGSample(s.ppg0, s.ppg1, s.ppg2, s.ambient, s.ppgDataSamples, s.ambient1, s.status));
743  }
744  return new PolarOhrPPGData(samples, ppgData.timeStamp, ppgData.type);
745  }
746  }).doFinally(new Action() {
747  @Override
748  public void run() throws Exception {
749  stopPmdStreaming(session, client, BlePMDClient.PmdMeasurementType.PPG);
750  }
751  })).onErrorResumeNext(new Function<Throwable, Publisher<? extends PolarOhrPPGData>>() {
752  @Override
753  public Publisher<? extends PolarOhrPPGData> apply(Throwable throwable) throws Exception {
754  return Flowable.error(handleError(throwable));
755  }
756  });
757  } catch (Throwable t) {
758  return Flowable.error(t);
759  }
760  }
761 
762  @Override
763  public Flowable<PolarOhrPPIData> startOhrPPIStreaming(String identifier) {
764  try {
765  final BleDeviceSession session = sessionPmdClientReady(identifier);
766  final BlePMDClient client = (BlePMDClient) session.fetchClient(BlePMDClient.PMD_SERVICE);
767  return client.startMeasurement(BlePMDClient.PmdMeasurementType.PPI, new BlePMDClient.PmdSetting(new HashMap<BlePMDClient.PmdSetting.PmdSettingType, Integer>())).andThen(
768  client.monitorPpiNotifications(true).map(new Function<BlePMDClient.PpiData, PolarOhrPPIData>() {
769  @Override
770  public PolarOhrPPIData apply(BlePMDClient.PpiData ppiData) throws Exception {
771  List<PolarOhrPPIData.PolarOhrPPISample> samples = new ArrayList<>();
772  for (BlePMDClient.PpiData.PPSample ppSample : ppiData.ppSamples) {
773  samples.add(new PolarOhrPPIData.PolarOhrPPISample(ppSample.ppInMs,
774  ppSample.ppErrorEstimate,
775  ppSample.hr,
776  ppSample.blockerBit != 0,
777  ppSample.skinContactStatus != 0,
778  ppSample.skinContactSupported != 0));
779  }
780  return new PolarOhrPPIData(ppiData.timestamp, samples);
781  }
782  }).doFinally(new Action() {
783  @Override
784  public void run() throws Exception {
785  stopPmdStreaming(session, client, BlePMDClient.PmdMeasurementType.PPI);
786  }
787  })).onErrorResumeNext(new Function<Throwable, Publisher<? extends PolarOhrPPIData>>() {
788  @Override
789  public Publisher<? extends PolarOhrPPIData> apply(Throwable throwable) throws Exception {
790  return Flowable.error(handleError(throwable));
791  }
792  });
793  } catch (Throwable t) {
794  return Flowable.error(t);
795  }
796  }
797 
798  @Override
799  public Flowable<PolarBiozData> startBiozStreaming(final String identifier, PolarSensorSetting setting) {
800  try {
801  final BleDeviceSession session = sessionPmdClientReady(identifier);
802  final BlePMDClient client = (BlePMDClient) session.fetchClient(BlePMDClient.PMD_SERVICE);
803  return client.startMeasurement(BlePMDClient.PmdMeasurementType.BIOZ, setting.map2PmdSettings()).andThen(
804  client.monitorBiozNotifications(true).map(new Function<BlePMDClient.BiozData, PolarBiozData>() {
805  @Override
806  public PolarBiozData apply(BlePMDClient.BiozData biozData) throws Exception {
807  return new PolarBiozData(biozData.timeStamp, biozData.samples, biozData.status, biozData.type);
808  }
809  }).doFinally(new Action() {
810  @Override
811  public void run() throws Exception {
812  stopPmdStreaming(session, client, BlePMDClient.PmdMeasurementType.PPG);
813  }
814  })).onErrorResumeNext(new Function<Throwable, Publisher<? extends PolarBiozData>>() {
815  @Override
816  public Publisher<? extends PolarBiozData> apply(Throwable throwable) throws Exception {
817  return Flowable.error(handleError(throwable));
818  }
819  });
820  } catch (Throwable t) {
821  return Flowable.error(t);
822  }
823  }
824 
825  protected BleDeviceSession fetchSession(final String identifier) throws PolarInvalidArgument {
826  if (identifier.matches("^([0-9A-Fa-f]{2}[:-]){5}([0-9A-Fa-f]{2})$")) {
827  return sessionByAddress(identifier);
828  } else if (identifier.matches("([0-9a-fA-F]){6,8}")) {
829  return sessionByDeviceId(identifier);
830  }
831  throw new PolarInvalidArgument();
832  }
833 
834  protected BleDeviceSession sessionByAddress(final String address) throws PolarInvalidArgument {
835  for (BleDeviceSession session : listener.deviceSessions()) {
836  if (session.getAddress().equals(address)) {
837  return session;
838  }
839  }
840  return null;
841  }
842 
843  protected BleDeviceSession sessionByDeviceId(final String deviceId) throws PolarInvalidArgument {
844  for (BleDeviceSession session : listener.deviceSessions()) {
845  if (session.getAdvertisementContent().getPolarDeviceId().equals(deviceId)) {
846  return session;
847  }
848  }
849  return null;
850  }
851 
852  protected BleDeviceSession sessionServiceReady(final String identifier, UUID service) throws Throwable {
853  BleDeviceSession session = fetchSession(identifier);
854  if (session != null) {
855  if (session.getSessionState() == SESSION_OPEN) {
856  BleGattBase client = session.fetchClient(service);
857  if (client.isServiceDiscovered()) {
858  return session;
859  }
860  throw new PolarServiceNotAvailable();
861  }
862  throw new PolarDeviceDisconnected();
863  }
864  throw new PolarDeviceNotFound();
865  }
866 
867  public BleDeviceSession sessionPmdClientReady(final String identifier) throws Throwable {
868  BleDeviceSession session = sessionServiceReady(identifier, BlePMDClient.PMD_SERVICE);
869  BlePMDClient client = (BlePMDClient) session.fetchClient(BlePMDClient.PMD_SERVICE);
870  final AtomicInteger pair = client.getNotificationAtomicInteger(BlePMDClient.PMD_CP);
871  final AtomicInteger pairData = client.getNotificationAtomicInteger(BlePMDClient.PMD_DATA);
872  if (pair != null && pairData != null &&
873  pair.get() == BleGattBase.ATT_SUCCESS &&
874  pairData.get() == BleGattBase.ATT_SUCCESS) {
875  return session;
876  }
877  throw new PolarNotificationNotEnabled();
878  }
879 
880  protected BleDeviceSession sessionPsFtpClientReady(final String identifier) throws Throwable {
881  BleDeviceSession session = sessionServiceReady(identifier, BlePsFtpUtils.RFC77_PFTP_SERVICE);
882  BlePsFtpClient client = (BlePsFtpClient) session.fetchClient(BlePsFtpUtils.RFC77_PFTP_SERVICE);
883  final AtomicInteger pair = client.getNotificationAtomicInteger(BlePsFtpUtils.RFC77_PFTP_MTU_CHARACTERISTIC);
884  if (pair != null && pair.get() == BleGattBase.ATT_SUCCESS) {
885  return session;
886  }
887  throw new PolarNotificationNotEnabled();
888  }
889 
890  @SuppressLint("CheckResult")
891  protected void stopPmdStreaming(BleDeviceSession session, BlePMDClient client, BlePMDClient.PmdMeasurementType type) {
892  if (session.getSessionState() == SESSION_OPEN) {
893  // stop streaming
894  client.stopMeasurement(type).subscribe(
895  new Action() {
896  @Override
897  public void run() throws Exception {
898 
899  }
900  },
901  new Consumer<Throwable>() {
902  @Override
903  public void accept(Throwable throwable) throws Exception {
904  logError("failed to stop pmd stream: " + throwable.getLocalizedMessage());
905  }
906  }
907  );
908  }
909  }
910 
911  @SuppressLint("CheckResult")
912  protected void setupDevice(final BleDeviceSession session) {
913  final String deviceId = session.getPolarDeviceId().length() != 0 ? session.getPolarDeviceId() : session.getAddress();
914  session.monitorServicesDiscovered(true).observeOn(scheduler).toFlowable().flatMapIterable(
915  new Function<List<UUID>, Iterable<UUID>>() {
916  @Override
917  public Iterable<UUID> apply(List<UUID> uuids) throws Exception {
918  return uuids;
919  }
920  }
921  ).flatMap(new Function<UUID, Publisher<?>>() {
922  @Override
923  public Publisher<?> apply(UUID uuid) throws Exception {
924  if (session.fetchClient(uuid) != null) {
925  if (uuid.equals(BleHrClient.HR_SERVICE)) {
926  if (callback != null) {
927  callback.hrFeatureReady(deviceId);
928  }
929  final BleHrClient client = (BleHrClient) session.fetchClient(BleHrClient.HR_SERVICE);
930  client.observeHrNotifications(true).observeOn(scheduler).subscribe(
931  new Consumer<BleHrClient.HrNotificationData>() {
932  @Override
933  public void accept(BleHrClient.HrNotificationData hrNotificationData) throws Exception {
934  if (callback != null) {
936  new PolarHrData(hrNotificationData.hrValue,
937  hrNotificationData.rrs,
938  hrNotificationData.sensorContact,
939  hrNotificationData.sensorContactSupported,
940  hrNotificationData.rrPresent));
941  }
942  }
943  },
944  new Consumer<Throwable>() {
945  @Override
946  public void accept(Throwable throwable) throws Exception {
947  logError(throwable.getMessage());
948  }
949  },
950  new Action() {
951  @Override
952  public void run() throws Exception {
953 
954  }
955  }
956  );
957  } else if (uuid.equals(BleBattClient.BATTERY_SERVICE)) {
958  BleBattClient client = (BleBattClient) session.fetchClient(BleBattClient.BATTERY_SERVICE);
959  return client.waitBatteryLevelUpdate(true).observeOn(scheduler).doOnSuccess(new Consumer<Integer>() {
960  @Override
961  public void accept(Integer integer) throws Exception {
962  if (callback != null) {
963  callback.batteryLevelReceived(deviceId, integer);
964  }
965  }
966  }).toFlowable();
967  } else if (uuid.equals(BlePMDClient.PMD_SERVICE)) {
968  final BlePMDClient client = (BlePMDClient) session.fetchClient(BlePMDClient.PMD_SERVICE);
969  return client.waitNotificationEnabled(BlePMDClient.PMD_CP, true).
970  concatWith(client.waitNotificationEnabled(BlePMDClient.PMD_DATA, true)).andThen(client.readFeature(true).doOnSuccess(new Consumer<BlePMDClient.PmdFeature>() {
971  @Override
972  public void accept(BlePMDClient.PmdFeature pmdFeature) {
973  if (callback != null) {
974  if (pmdFeature.ecgSupported) {
975  callback.ecgFeatureReady(deviceId);
976  }
977  if (pmdFeature.accSupported) {
979  }
980  if (pmdFeature.ppgSupported) {
981  callback.ppgFeatureReady(deviceId);
982  }
983  if (pmdFeature.ppiSupported) {
984  callback.ppiFeatureReady(deviceId);
985  }
986  if (pmdFeature.bioZSupported) {
987  callback.biozFeatureReady(deviceId);
988  }
989  }
990  }
991  })).toFlowable();
992  } else if (uuid.equals(BleDisClient.DIS_SERVICE)) {
993  BleDisClient client = (BleDisClient) session.fetchClient(BleDisClient.DIS_SERVICE);
994  return client.observeDisInfo(true).observeOn(scheduler).doOnNext(new Consumer<Pair<UUID, String>>() {
995  @Override
996  public void accept(Pair<UUID, String> pair) {
997  if (callback != null) {
998  callback.disInformationReceived(deviceId, pair.first, pair.second);
999  }
1000  }
1001  });
1002  } else if (uuid.equals(BlePsFtpUtils.RFC77_PFTP_SERVICE)) {
1003  BlePsFtpClient client = (BlePsFtpClient) session.fetchClient(BlePsFtpUtils.RFC77_PFTP_SERVICE);
1004  return client.waitPsFtpClientReady(true).observeOn(scheduler).doOnComplete(new Action() {
1005  @Override
1006  public void run() throws Exception {
1007  if (callback != null &&
1008  (session.getPolarDeviceType().equals("OH1") || session.getPolarDeviceType().equals("H10"))) {
1009  callback.polarFtpFeatureReady(deviceId);
1010  }
1011  }
1012  }).toFlowable();
1013  }
1014  }
1015  return Flowable.empty();
1016  }
1017  }).subscribe(
1018  new Consumer<Object>() {
1019  @Override
1020  public void accept(Object o) throws Exception {
1021 
1022  }
1023  },
1024  new Consumer<Throwable>() {
1025  @Override
1026  public void accept(Throwable throwable) throws Exception {
1027  logError(throwable.getMessage());
1028  }
1029  },
1030  new Action() {
1031  @Override
1032  public void run() throws Exception {
1033  log("complete");
1034  }
1035  });
1036  }
1037 
1038  protected Exception handleError(Throwable throwable) {
1039  if (throwable instanceof BleDisconnected) {
1040  return new PolarDeviceDisconnected();
1041  } else {
1042  return new Exception("Unknown Error: " + throwable.getLocalizedMessage());
1043  }
1044  }
1045 
1046  @Override
1047  public void stateChanged(BleDeviceSession session, BleDeviceSession.DeviceSessionState sessionState) {
1048  PolarDeviceInfo info = new PolarDeviceInfo(
1049  session.getPolarDeviceId().length() != 0 ?
1050  session.getPolarDeviceId() : session.getAddress(),
1051  session.getAddress(),
1052  session.getRssi(), session.getName(), true);
1053  switch (sessionState) {
1054  case SESSION_OPEN:
1055  if (callback != null) {
1056  callback.deviceConnected(info);
1057  }
1058  setupDevice(session);
1059  break;
1060  case SESSION_CLOSED:
1061  if (callback != null) {
1062  if (session.getPreviousState() == SESSION_OPEN ||
1063  session.getPreviousState() == BleDeviceSession.DeviceSessionState.SESSION_CLOSING) {
1065  }
1066  }
1067  break;
1068  case SESSION_OPENING:
1069  if (callback != null) {
1070  callback.deviceConnecting(info);
1071  }
1072  break;
1073  }
1074  }
1075 
1076  @Override
1077  public void stateChanged(Boolean power) {
1078  if (callback != null) {
1080  }
1081  }
1082 
1083  interface FetchRecursiveCondition {
1084  boolean include(String entry);
1085  }
1086 
1087  protected Flowable<String> fetchRecursively(final BlePsFtpClient client, final String path, final FetchRecursiveCondition condition) {
1088  protocol.PftpRequest.PbPFtpOperation.Builder builder = protocol.PftpRequest.PbPFtpOperation.newBuilder();
1089  builder.setCommand(PftpRequest.PbPFtpOperation.Command.GET);
1090  builder.setPath(path);
1091  return client.request(builder.build().toByteArray()).toFlowable().flatMap(new Function<ByteArrayOutputStream, Publisher<String>>() {
1092  @Override
1093  public Publisher<String> apply(ByteArrayOutputStream byteArrayOutputStream) throws Exception {
1094  PftpResponse.PbPFtpDirectory dir = PftpResponse.PbPFtpDirectory.parseFrom(byteArrayOutputStream.toByteArray());
1095  Set<String> entrys = new HashSet<>();
1096  for (int i = 0; i < dir.getEntriesCount(); ++i) {
1097  PftpResponse.PbPFtpEntry entry = dir.getEntries(i);
1098  if (condition.include(entry.getName())) {
1099  BleUtils.validate(entrys.add(path + entry.getName()), "duplicate entry");
1100  }
1101  }
1102  if (entrys.size() != 0) {
1103  return Flowable.fromIterable(entrys).flatMap(new Function<String, Publisher<String>>() {
1104  @Override
1105  public Publisher<String> apply(String s) {
1106  if (s.endsWith("/")) {
1107  return fetchRecursively(client, s, condition);
1108  } else {
1109  return Flowable.just(s);
1110  }
1111  }
1112  });
1113  }
1114  return Flowable.empty();
1115  }
1116  });
1117  }
1118 
1119  protected void log(final String message) {
1120  if (logger != null) {
1121  logger.message("" + message);
1122  }
1123  }
1124 
1125  protected void logError(final String message) {
1126  if (logger != null) {
1127  logger.message("Error: " + message);
1128  }
1129  }
1130 }
+
void log(final String message)
void polarFtpFeatureReady(@NonNull final String identifier)
void batteryLevelReceived(@NonNull final String identifier, final int level)
-
Single< PolarExerciseData > fetchExercise(String identifier, PolarExerciseEntry entry)
- -
Completable startRecording(String identifier, String exerciseId, RecordingInterval interval, SampleType type)
-
Completable autoConnectToDevice(final int rssiLimit, final String service, final int timeout, final TimeUnit unit, final String polarDeviceType)
+
Single< PolarExerciseData > fetchExercise(String identifier, PolarExerciseEntry entry)
+ +
Completable startRecording(String identifier, String exerciseId, RecordingInterval interval, SampleType type)
+
Completable autoConnectToDevice(final int rssiLimit, final String service, final int timeout, final TimeUnit unit, final String polarDeviceType)
-
void setAutomaticReconnection(boolean disable)
-
Single< PolarSensorSetting > requestAccSettings(String identifier)
+
void setAutomaticReconnection(boolean disable)
+
Single< PolarSensorSetting > requestAccSettings(String identifier)
void deviceConnected(@NonNull final PolarDeviceInfo polarDeviceInfo)
-
Exception handleError(Throwable throwable)
+
Exception handleError(Throwable throwable)
-
Flowable< PolarOhrPPIData > startOhrPPIStreaming(String identifier)
+
Flowable< PolarOhrPPIData > startOhrPPIStreaming(String identifier)
void hrFeatureReady(@NonNull final String identifier)
-
Flowable< PolarHrBroadcastData > startListenForPolarHrBroadcasts(final Set< String > deviceIds)
+
Flowable< PolarHrBroadcastData > startListenForPolarHrBroadcasts(final Set< String > deviceIds)
-
Flowable< PolarDeviceInfo > searchForDevice()
+
Flowable< PolarDeviceInfo > searchForDevice()
- -
Single< PolarSensorSetting > querySettings(final String identifier, final BlePMDClient.PmdMeasurementType type)
+ +
Single< PolarSensorSetting > querySettings(final String identifier, final BlePMDClient.PmdMeasurementType type)
static final int FEATURE_POLAR_SENSOR_STREAMING
-
Single< PolarSensorSetting > requestBiozSettings(final String identifier)
- +
Single< PolarSensorSetting > requestBiozSettings(final String identifier)
+ -
Single< PolarSensorSetting > requestEcgSettings(String identifier)
-
BleDeviceSession sessionServiceReady(final String identifier, UUID service)
+
Single< PolarSensorSetting > requestEcgSettings(String identifier)
+
BleDeviceSession sessionServiceReady(final String identifier, UUID service)
void deviceDisconnected(@NonNull final PolarDeviceInfo polarDeviceInfo)
@@ -111,56 +111,57 @@
static final int FEATURE_BATTERY_INFO
-
BleDeviceSession fetchSession(final String identifier)
-
void stateChanged(Boolean power)
+
BleDeviceSession fetchSession(final String identifier)
+
void stateChanged(Boolean power)
void ppiFeatureReady(@NonNull final String identifier)
void ppgFeatureReady(@NonNull final String identifier)
-
boolean isFeatureReady(final String deviceId, int feature)
-
Single< Pair< Boolean, String > > requestRecordingStatus(String identifier)
+
boolean isFeatureReady(final String deviceId, int feature)
+
Single< Pair< Boolean, String > > requestRecordingStatus(String identifier)
Map< String, Disposable > connectSubscriptions
-
BleDeviceSession sessionByAddress(final String address)
+
BleDeviceSession sessionByAddress(final String address)
void blePowerStateChanged(final boolean powered)
-
Flowable< PolarAccelerometerData > startAccStreaming(String identifier, PolarSensorSetting setting)
+
Flowable< PolarAccelerometerData > startAccStreaming(String identifier, PolarSensorSetting setting)
BDBleApiImpl(final Context context, int features)
-
Single< PolarSensorSetting > requestPpgSettings(String identifier)
+
Single< PolarSensorSetting > requestPpgSettings(String identifier)
-
BleDeviceSession sessionPmdClientReady(final String identifier)
+
BleDeviceSession sessionPmdClientReady(final String identifier)
-
Flowable< String > fetchRecursively(final BlePsFtpClient client, final String path, final FetchRecursiveCondition condition)
-
Completable stopRecording(String identifier)
+
Flowable< String > fetchRecursively(final BlePsFtpClient client, final String path, final FetchRecursiveCondition condition)
+
Completable stopRecording(String identifier)
void biozFeatureReady(@NonNull final String identifier)
PolarBleApiCallbackProvider callback
static final int FEATURE_DEVICE_INFO
void accelerometerFeatureReady(@NonNull final String identifier)
-
void setupDevice(final BleDeviceSession session)
+
void setupDevice(final BleDeviceSession session)
-
void connectToDevice(final String identifier)
-
Flowable< PolarBiozData > startBiozStreaming(final String identifier, PolarSensorSetting setting)
-
Flowable< PolarExerciseEntry > listExercises(String identifier)
+
void connectToDevice(final String identifier)
+
Flowable< PolarBiozData > startBiozStreaming(final String identifier, PolarSensorSetting setting)
+
Flowable< PolarExerciseEntry > listExercises(String identifier)
-
Completable autoConnectToDevice(final int rssiLimit, final String service, final String polarDeviceType)
+
Completable autoConnectToDevice(final int rssiLimit, final String service, final String polarDeviceType)
-
BleDeviceSession sessionByDeviceId(final String deviceId)
-
void setPolarFilter(boolean enable)
-
void setApiCallback(PolarBleApiCallbackProvider callback)
+
BleDeviceSession sessionByDeviceId(final String deviceId)
+
void setPolarFilter(boolean enable)
+
void setApiCallback(PolarBleApiCallbackProvider callback)
static final int FEATURE_POLAR_FILE_TRANSFER
-
Completable removeExercise(String identifier, PolarExerciseEntry entry)
+
Completable removeExercise(String identifier, PolarExerciseEntry entry)
void disInformationReceived(@NonNull final String identifier, @NonNull UUID uuid, @NonNull final String value)
-
void stateChanged(BleDeviceSession session, BleDeviceSession.DeviceSessionState sessionState)
+
void stateChanged(BleDeviceSession session, BleDeviceSession.DeviceSessionState sessionState)
void deviceConnecting(@NonNull final PolarDeviceInfo polarDeviceInfo)
-
void stopPmdStreaming(BleDeviceSession session, BlePMDClient client, BlePMDClient.PmdMeasurementType type)
- -
void setApiLogger(@Nullable PolarBleApiLogger logger)
-
Flowable< PolarOhrPPGData > startOhrPPGStreaming(String identifier, PolarSensorSetting setting)
-
Flowable< PolarEcgData > startEcgStreaming(String identifier, PolarSensorSetting setting)
+
void stopPmdStreaming(BleDeviceSession session, BlePMDClient client, BlePMDClient.PmdMeasurementType type)
+ +
void setApiLogger(@Nullable PolarBleApiLogger logger)
+ +
Flowable< PolarOhrPPGData > startOhrPPGStreaming(String identifier, PolarSensorSetting setting)
+
Flowable< PolarEcgData > startEcgStreaming(String identifier, PolarSensorSetting setting)
void hrNotificationReceived(@NonNull final String identifier, @NonNull final PolarHrData data)
void ecgFeatureReady(@NonNull final String identifier)
@@ -170,14 +171,14 @@ -
Completable setLocalTime(String identifier, Calendar cal)
+
Completable setLocalTime(String identifier, Calendar cal)
-
BleDeviceSession sessionPsFtpClientReady(final String identifier)
-
void logError(final String message)
+
BleDeviceSession sessionPsFtpClientReady(final String identifier)
+
void logError(final String message)
-
void disconnectFromDevice(String identifier)
+
void disconnectFromDevice(String identifier)
diff --git a/polar-sdk-android/docs/html/PolarBleApiDefaultImpl_8java_source.html b/polar-sdk-android/docs/html/PolarBleApiDefaultImpl_8java_source.html index 6dcaedff..67fcee4a 100644 --- a/polar-sdk-android/docs/html/PolarBleApiDefaultImpl_8java_source.html +++ b/polar-sdk-android/docs/html/PolarBleApiDefaultImpl_8java_source.html @@ -66,7 +66,7 @@
PolarBleApiDefaultImpl.java
-Go to the documentation of this file.
1 // Copyright © 2019 Polar Electro Oy. All rights reserved.
2 package polar.com.sdk.api;
3 
4 import android.content.Context;
5 
7 
11 public class PolarBleApiDefaultImpl {
18  public static PolarBleApi defaultImplementation(final Context context, int features){
19  return new BDBleApiImpl(context,features);
20  }
21 
25  public static String versionInfo(){
26  return "2.2.1";
27  }
28 }
+Go to the documentation of this file.
1 // Copyright © 2019 Polar Electro Oy. All rights reserved.
2 package polar.com.sdk.api;
3 
4 import android.content.Context;
5 
7 
11 public class PolarBleApiDefaultImpl {
18  public static PolarBleApi defaultImplementation(final Context context, int features){
19  return new BDBleApiImpl(context,features);
20  }
21 
25  public static String versionInfo(){
26  return "2.2.2";
27  }
28 }
diff --git a/polar-sdk-android/docs/html/PolarBleApi_8java_source.html b/polar-sdk-android/docs/html/PolarBleApi_8java_source.html index 45853a2f..a93d4286 100644 --- a/polar-sdk-android/docs/html/PolarBleApi_8java_source.html +++ b/polar-sdk-android/docs/html/PolarBleApi_8java_source.html @@ -66,7 +66,7 @@
PolarBleApi.java
-Go to the documentation of this file.
1 // Copyright © 2019 Polar Electro Oy. All rights reserved.
2 package polar.com.sdk.api;
3 
4 import android.support.annotation.Nullable;
5 import android.support.annotation.Size;
6 import android.util.Pair;
7 
8 import java.util.Calendar;
9 import java.util.Date;
10 import java.util.Set;
11 import java.util.concurrent.TimeUnit;
12 
13 import io.reactivex.Completable;
14 import io.reactivex.Flowable;
15 import io.reactivex.Single;
16 import io.reactivex.annotations.NonNull;
28 
32 public abstract class PolarBleApi {
33 
37  public interface PolarBleApiLogger {
42  void message(final String str);
43  }
44 
48  public enum RecordingInterval {
52  private int value;
53 
54  RecordingInterval(int value) {
55  this.value = value;
56  }
57 
58  public int getValue() {
59  return value;
60  }
61  }
62 
66  public enum SampleType {
67  HR,
68  RR;
69  }
70 
74  public static final int FEATURE_HR = 1;
78  public static final int FEATURE_DEVICE_INFO = 2;
82  public static final int FEATURE_BATTERY_INFO = 4;
86  public static final int FEATURE_POLAR_SENSOR_STREAMING = 8;
90  public static final int FEATURE_POLAR_FILE_TRANSFER = 16;
94  public static final int ALL_FEATURES = 0xff;
95 
96  protected int features;
97 
102  protected PolarBleApi(final int features) {
103  this.features = features;
104  }
105 
109  public abstract void shutDown();
110 
114  public abstract void cleanup();
115 
120  public abstract void setPolarFilter(boolean enable);
121 
128  public abstract boolean isFeatureReady(@NonNull final String deviceId, final int feature);
129 
133  public abstract void backgroundEntered();
134 
138  public abstract void foregroundEntered();
139 
143  public abstract void setApiCallback(@Nullable PolarBleApiCallbackProvider callback);
144 
148  public abstract void setApiLogger(@Nullable PolarBleApiLogger logger);
149 
154  public abstract void setAutomaticReconnection(boolean enable);
155 
163  public abstract Completable setLocalTime(@NonNull final String identifier, @NonNull Calendar calendar);
164 
170  public abstract Single<PolarSensorSetting> requestAccSettings(@NonNull final String identifier);
171 
177  public abstract Single<PolarSensorSetting> requestEcgSettings(@NonNull final String identifier);
178 
184  public abstract Single<PolarSensorSetting> requestPpgSettings(@NonNull final String identifier);
185 
186  public abstract Single<PolarSensorSetting> requestBiozSettings(@NonNull final String identifier);
187 
199  public abstract Completable autoConnectToDevice(int rssiLimit, @Nullable String service, int timeout,@NonNull TimeUnit unit,@Nullable final String polarDeviceType);
200  public abstract Completable autoConnectToDevice(int rssiLimit, @Nullable String service, final String polarDeviceType);
201 
207  public abstract void connectToDevice(@NonNull final String identifier) throws PolarInvalidArgument;
208 
214  public abstract void disconnectFromDevice(@NonNull final String identifier) throws PolarInvalidArgument;
215 
224  public abstract Completable startRecording(@NonNull final String identifier,
225  @NonNull @Size(min = 1, max = 64) final String exerciseId,
226  @NonNull RecordingInterval interval,
227  @NonNull SampleType type);
228 
234  public abstract Completable stopRecording(@NonNull final String identifier);
235 
241  public abstract Single<Pair<Boolean,String>> requestRecordingStatus(@NonNull final String identifier);
242 
248  public abstract Flowable<PolarExerciseEntry> listExercises(@NonNull final String identifier);
249 
256  public abstract Single<PolarExerciseData> fetchExercise(@NonNull final String identifier, @NonNull final PolarExerciseEntry entry);
257 
264  public abstract Completable removeExercise(@NonNull final String identifier, @NonNull final PolarExerciseEntry entry);
265 
274  public abstract Flowable<PolarDeviceInfo> searchForDevice();
275 
285  public abstract Flowable<PolarHrBroadcastData> startListenForPolarHrBroadcasts(@Nullable final Set<String> deviceIds);
286 
299  public abstract Flowable<PolarEcgData> startEcgStreaming(@NonNull final String identifier,
300  @NonNull PolarSensorSetting sensorSetting);
301 
314  public abstract Flowable<PolarAccelerometerData> startAccStreaming(@NonNull final String identifier,
315  @NonNull PolarSensorSetting sensorSetting);
316 
329  public abstract Flowable<PolarOhrPPGData> startOhrPPGStreaming(@NonNull final String identifier,
330  @NonNull PolarSensorSetting sensorSetting);
331 
332  public abstract Flowable<PolarBiozData> startBiozStreaming(@NonNull final String identifier,
333  @NonNull PolarSensorSetting sensorSetting);
334 
345  public abstract Flowable<PolarOhrPPIData> startOhrPPIStreaming(@NonNull final String identifier);
346 }
+Go to the documentation of this file.
1 // Copyright © 2019 Polar Electro Oy. All rights reserved.
2 package polar.com.sdk.api;
3 
4 import android.support.annotation.IntRange;
5 import android.support.annotation.Nullable;
6 import android.support.annotation.Size;
7 import android.util.Pair;
8 
9 import java.util.Calendar;
10 import java.util.Set;
11 import java.util.concurrent.TimeUnit;
12 
13 import io.reactivex.Completable;
14 import io.reactivex.Flowable;
15 import io.reactivex.Single;
16 import io.reactivex.annotations.NonNull;
28 
32 public abstract class PolarBleApi {
33 
37  public interface PolarBleApiLogger {
42  void message(final String str);
43  }
44 
48  public enum RecordingInterval {
52  private int value;
53 
54  RecordingInterval(int value) {
55  this.value = value;
56  }
57 
58  public int getValue() {
59  return value;
60  }
61  }
62 
66  public enum SampleType {
67  HR,
68  RR;
69  }
70 
74  public static final int FEATURE_HR = 1;
78  public static final int FEATURE_DEVICE_INFO = 2;
82  public static final int FEATURE_BATTERY_INFO = 4;
86  public static final int FEATURE_POLAR_SENSOR_STREAMING = 8;
90  public static final int FEATURE_POLAR_FILE_TRANSFER = 16;
94  public static final int ALL_FEATURES = 0xff;
95 
96  protected int features;
97 
102  protected PolarBleApi(final int features) {
103  this.features = features;
104  }
105 
111  public abstract void setMtu(@IntRange(from = 70, to = 512) int mtu);
112 
116  public abstract void shutDown();
117 
121  public abstract void cleanup();
122 
127  public abstract void setPolarFilter(boolean enable);
128 
135  public abstract boolean isFeatureReady(@NonNull final String deviceId, final int feature);
136 
140  public abstract void backgroundEntered();
141 
145  public abstract void foregroundEntered();
146 
150  public abstract void setApiCallback(@Nullable PolarBleApiCallbackProvider callback);
151 
155  public abstract void setApiLogger(@Nullable PolarBleApiLogger logger);
156 
161  public abstract void setAutomaticReconnection(boolean enable);
162 
170  public abstract Completable setLocalTime(@NonNull final String identifier, @NonNull Calendar calendar);
171 
177  public abstract Single<PolarSensorSetting> requestAccSettings(@NonNull final String identifier);
178 
184  public abstract Single<PolarSensorSetting> requestEcgSettings(@NonNull final String identifier);
185 
191  public abstract Single<PolarSensorSetting> requestPpgSettings(@NonNull final String identifier);
192 
193  public abstract Single<PolarSensorSetting> requestBiozSettings(@NonNull final String identifier);
194 
206  public abstract Completable autoConnectToDevice(int rssiLimit, @Nullable String service, int timeout,@NonNull TimeUnit unit,@Nullable final String polarDeviceType);
207  public abstract Completable autoConnectToDevice(int rssiLimit, @Nullable String service, final String polarDeviceType);
208 
214  public abstract void connectToDevice(@NonNull final String identifier) throws PolarInvalidArgument;
215 
221  public abstract void disconnectFromDevice(@NonNull final String identifier) throws PolarInvalidArgument;
222 
231  public abstract Completable startRecording(@NonNull final String identifier,
232  @NonNull @Size(min = 1, max = 64) final String exerciseId,
233  @NonNull RecordingInterval interval,
234  @NonNull SampleType type);
235 
241  public abstract Completable stopRecording(@NonNull final String identifier);
242 
248  public abstract Single<Pair<Boolean,String>> requestRecordingStatus(@NonNull final String identifier);
249 
255  public abstract Flowable<PolarExerciseEntry> listExercises(@NonNull final String identifier);
256 
263  public abstract Single<PolarExerciseData> fetchExercise(@NonNull final String identifier, @NonNull final PolarExerciseEntry entry);
264 
271  public abstract Completable removeExercise(@NonNull final String identifier, @NonNull final PolarExerciseEntry entry);
272 
281  public abstract Flowable<PolarDeviceInfo> searchForDevice();
282 
292  public abstract Flowable<PolarHrBroadcastData> startListenForPolarHrBroadcasts(@Nullable final Set<String> deviceIds);
293 
306  public abstract Flowable<PolarEcgData> startEcgStreaming(@NonNull final String identifier,
307  @NonNull PolarSensorSetting sensorSetting);
308 
321  public abstract Flowable<PolarAccelerometerData> startAccStreaming(@NonNull final String identifier,
322  @NonNull PolarSensorSetting sensorSetting);
323 
336  public abstract Flowable<PolarOhrPPGData> startOhrPPGStreaming(@NonNull final String identifier,
337  @NonNull PolarSensorSetting sensorSetting);
338 
339  public abstract Flowable<PolarBiozData> startBiozStreaming(@NonNull final String identifier,
340  @NonNull PolarSensorSetting sensorSetting);
341 
352  public abstract Flowable<PolarOhrPPIData> startOhrPPIStreaming(@NonNull final String identifier);
353 }
abstract Single< PolarSensorSetting > requestEcgSettings(@NonNull final String identifier)
abstract Flowable< PolarOhrPPIData > startOhrPPIStreaming(@NonNull final String identifier)
@@ -120,6 +120,7 @@
abstract Completable removeExercise(@NonNull final String identifier, @NonNull final PolarExerciseEntry entry)
abstract void setApiCallback(@Nullable PolarBleApiCallbackProvider callback)
abstract Flowable< PolarDeviceInfo > searchForDevice()
+
abstract void setMtu(@IntRange(from=70, to=512) int mtu)
static final int FEATURE_POLAR_FILE_TRANSFER
abstract Flowable< PolarEcgData > startEcgStreaming(@NonNull final String identifier, @NonNull PolarSensorSetting sensorSetting)
abstract Single< PolarSensorSetting > requestPpgSettings(@NonNull final String identifier)
diff --git a/polar-sdk-android/docs/html/classpolar_1_1com_1_1sdk_1_1api_1_1PolarBleApi.html b/polar-sdk-android/docs/html/classpolar_1_1com_1_1sdk_1_1api_1_1PolarBleApi.html index d1d63379..08ae6dad 100644 --- a/polar-sdk-android/docs/html/classpolar_1_1com_1_1sdk_1_1api_1_1PolarBleApi.html +++ b/polar-sdk-android/docs/html/classpolar_1_1com_1_1sdk_1_1api_1_1PolarBleApi.html @@ -93,6 +93,8 @@ + + @@ -976,6 +978,38 @@

Returns
Completable stream
+ + +
+

◆ setMtu()

+ +
+
+

Public Member Functions

abstract void setMtu (@IntRange(from=70, to=512) int mtu)
 
abstract void shutDown ()
 
abstract void cleanup ()
+ + + + +
+ + + + + + + + +
abstract void polar.com.sdk.api.PolarBleApi.setMtu (@IntRange(from=70, to=512) int mtu)
+
+abstract
+
+

set mtu to lower than default(232 is the default for polar devices, minimum for H10 is 70 and for OH1 is 140) to minimize latency

Parameters
+ + +
mtuvalue between 64-512 to be set
+
+
+
diff --git a/polar-sdk-android/docs/html/classpolar_1_1com_1_1sdk_1_1api_1_1PolarBleApi.js b/polar-sdk-android/docs/html/classpolar_1_1com_1_1sdk_1_1api_1_1PolarBleApi.js index 20aa8837..7136249a 100644 --- a/polar-sdk-android/docs/html/classpolar_1_1com_1_1sdk_1_1api_1_1PolarBleApi.js +++ b/polar-sdk-android/docs/html/classpolar_1_1com_1_1sdk_1_1api_1_1PolarBleApi.js @@ -25,6 +25,7 @@ var classpolar_1_1com_1_1sdk_1_1api_1_1PolarBleApi = [ "setApiLogger", "classpolar_1_1com_1_1sdk_1_1api_1_1PolarBleApi.html#ac92b34d91563bb7a208818dd4358b260", null ], [ "setAutomaticReconnection", "classpolar_1_1com_1_1sdk_1_1api_1_1PolarBleApi.html#a32484f5b3bacdde45573298a4e1d12a5", null ], [ "setLocalTime", "classpolar_1_1com_1_1sdk_1_1api_1_1PolarBleApi.html#ac8923ad69235615e62262a25115a01b9", null ], + [ "setMtu", "classpolar_1_1com_1_1sdk_1_1api_1_1PolarBleApi.html#a17372e01394efb53e7c8f83cb0e379eb", null ], [ "setPolarFilter", "classpolar_1_1com_1_1sdk_1_1api_1_1PolarBleApi.html#ae7a6e7c991db4f0fecca383e639cc74c", null ], [ "shutDown", "classpolar_1_1com_1_1sdk_1_1api_1_1PolarBleApi.html#ab6dec221f95ea5dce6118cadeb362006", null ], [ "startAccStreaming", "classpolar_1_1com_1_1sdk_1_1api_1_1PolarBleApi.html#a11aa139fffa100c346c13a23fdedfe71", null ], diff --git a/polar-sdk-android/docs/html/classpolar_1_1com_1_1sdk_1_1impl_1_1BDBleApiImpl.html b/polar-sdk-android/docs/html/classpolar_1_1com_1_1sdk_1_1impl_1_1BDBleApiImpl.html index 616d092b..1264c7f7 100644 --- a/polar-sdk-android/docs/html/classpolar_1_1com_1_1sdk_1_1impl_1_1BDBleApiImpl.html +++ b/polar-sdk-android/docs/html/classpolar_1_1com_1_1sdk_1_1impl_1_1BDBleApiImpl.html @@ -91,6 +91,8 @@ Public Member Functions  BDBleApiImpl (final Context context, int features)   +void setMtu (int mtu) +  void shutDown ()   void cleanup () @@ -160,6 +162,8 @@ void stateChanged (Boolean power)   - Public Member Functions inherited from polar.com.sdk.api.PolarBleApi +abstract void setMtu (@IntRange(from=70, to=512) int mtu) +  abstract void shutDown ()   abstract void cleanup () @@ -390,7 +394,7 @@

-

Definition at line 285 of file BDBleApiImpl.java.

+

Definition at line 290 of file BDBleApiImpl.java.

@@ -434,7 +438,7 @@

-

Definition at line 339 of file BDBleApiImpl.java.

+

Definition at line 344 of file BDBleApiImpl.java.

@@ -461,7 +465,7 @@

-

Definition at line 275 of file BDBleApiImpl.java.

+

Definition at line 280 of file BDBleApiImpl.java.

@@ -488,7 +492,7 @@

-

Definition at line 174 of file BDBleApiImpl.java.

+

Definition at line 179 of file BDBleApiImpl.java.

@@ -516,7 +520,7 @@

-

Definition at line 344 of file BDBleApiImpl.java.

+

Definition at line 349 of file BDBleApiImpl.java.

@@ -544,7 +548,7 @@

-

Definition at line 386 of file BDBleApiImpl.java.

+

Definition at line 391 of file BDBleApiImpl.java.

@@ -609,7 +613,7 @@

-

Definition at line 527 of file BDBleApiImpl.java.

+

Definition at line 532 of file BDBleApiImpl.java.

@@ -653,7 +657,7 @@

-

Definition at line 1082 of file BDBleApiImpl.java.

+

Definition at line 1087 of file BDBleApiImpl.java.

@@ -681,7 +685,7 @@

-

Definition at line 820 of file BDBleApiImpl.java.

+

Definition at line 825 of file BDBleApiImpl.java.

@@ -708,7 +712,7 @@

-

Definition at line 280 of file BDBleApiImpl.java.

+

Definition at line 285 of file BDBleApiImpl.java.

@@ -736,7 +740,7 @@

-

Definition at line 1033 of file BDBleApiImpl.java.

+

Definition at line 1038 of file BDBleApiImpl.java.

@@ -774,7 +778,7 @@

-

Definition at line 188 of file BDBleApiImpl.java.

+

Definition at line 193 of file BDBleApiImpl.java.

@@ -802,7 +806,7 @@

-

Definition at line 471 of file BDBleApiImpl.java.

+

Definition at line 476 of file BDBleApiImpl.java.

@@ -830,7 +834,7 @@

-

Definition at line 1114 of file BDBleApiImpl.java.

+

Definition at line 1119 of file BDBleApiImpl.java.

@@ -858,7 +862,7 @@

-

Definition at line 1120 of file BDBleApiImpl.java.

+

Definition at line 1125 of file BDBleApiImpl.java.

@@ -896,7 +900,7 @@

-

Definition at line 259 of file BDBleApiImpl.java.

+

Definition at line 264 of file BDBleApiImpl.java.

@@ -934,7 +938,7 @@

-

Definition at line 575 of file BDBleApiImpl.java.

+

Definition at line 580 of file BDBleApiImpl.java.

@@ -962,7 +966,7 @@

-

Definition at line 240 of file BDBleApiImpl.java.

+

Definition at line 245 of file BDBleApiImpl.java.

@@ -990,7 +994,7 @@

-

Definition at line 255 of file BDBleApiImpl.java.

+

Definition at line 260 of file BDBleApiImpl.java.

@@ -1018,7 +1022,7 @@

-

Definition at line 245 of file BDBleApiImpl.java.

+

Definition at line 250 of file BDBleApiImpl.java.

@@ -1046,7 +1050,7 @@

-

Definition at line 250 of file BDBleApiImpl.java.

+

Definition at line 255 of file BDBleApiImpl.java.

@@ -1074,7 +1078,7 @@

-

Definition at line 446 of file BDBleApiImpl.java.

+

Definition at line 451 of file BDBleApiImpl.java.

@@ -1101,7 +1105,7 @@

-

Definition at line 624 of file BDBleApiImpl.java.

+

Definition at line 629 of file BDBleApiImpl.java.

@@ -1129,7 +1133,7 @@

-

Definition at line 829 of file BDBleApiImpl.java.

+

Definition at line 834 of file BDBleApiImpl.java.

@@ -1157,7 +1161,7 @@

-

Definition at line 838 of file BDBleApiImpl.java.

+

Definition at line 843 of file BDBleApiImpl.java.

@@ -1185,7 +1189,7 @@

-

Definition at line 862 of file BDBleApiImpl.java.

+

Definition at line 867 of file BDBleApiImpl.java.

@@ -1213,7 +1217,7 @@

-

Definition at line 875 of file BDBleApiImpl.java.

+

Definition at line 880 of file BDBleApiImpl.java.

@@ -1251,7 +1255,7 @@

-

Definition at line 847 of file BDBleApiImpl.java.

+

Definition at line 852 of file BDBleApiImpl.java.

@@ -1279,7 +1283,7 @@

-

Definition at line 202 of file BDBleApiImpl.java.

+

Definition at line 207 of file BDBleApiImpl.java.

@@ -1307,7 +1311,7 @@

-

Definition at line 208 of file BDBleApiImpl.java.

+

Definition at line 213 of file BDBleApiImpl.java.

@@ -1335,7 +1339,7 @@

-

Definition at line 213 of file BDBleApiImpl.java.

+

Definition at line 218 of file BDBleApiImpl.java.

@@ -1373,7 +1377,35 @@

-

Definition at line 218 of file BDBleApiImpl.java.

+

Definition at line 223 of file BDBleApiImpl.java.

+ + + + +

◆ setMtu()

+ +
+
+ + + + + +
+ + + + + + + + +
void polar.com.sdk.impl.BDBleApiImpl.setMtu (int mtu)
+
+inline
+
+ +

Definition at line 169 of file BDBleApiImpl.java.

@@ -1401,7 +1433,7 @@

-

Definition at line 179 of file BDBleApiImpl.java.

+

Definition at line 184 of file BDBleApiImpl.java.

@@ -1429,7 +1461,7 @@

-

Definition at line 907 of file BDBleApiImpl.java.

+

Definition at line 912 of file BDBleApiImpl.java.

@@ -1456,7 +1488,7 @@

-

Definition at line 169 of file BDBleApiImpl.java.

+

Definition at line 174 of file BDBleApiImpl.java.

@@ -1494,7 +1526,7 @@

-

Definition at line 694 of file BDBleApiImpl.java.

+

Definition at line 699 of file BDBleApiImpl.java.

@@ -1532,7 +1564,7 @@

-

Definition at line 794 of file BDBleApiImpl.java.

+

Definition at line 799 of file BDBleApiImpl.java.

@@ -1570,7 +1602,7 @@

-

Definition at line 662 of file BDBleApiImpl.java.

+

Definition at line 667 of file BDBleApiImpl.java.

@@ -1598,7 +1630,7 @@

-

Definition at line 638 of file BDBleApiImpl.java.

+

Definition at line 643 of file BDBleApiImpl.java.

@@ -1636,7 +1668,7 @@

-

Definition at line 726 of file BDBleApiImpl.java.

+

Definition at line 731 of file BDBleApiImpl.java.

@@ -1664,7 +1696,7 @@

-

Definition at line 758 of file BDBleApiImpl.java.

+

Definition at line 763 of file BDBleApiImpl.java.

@@ -1714,7 +1746,7 @@

-

Definition at line 402 of file BDBleApiImpl.java.

+

Definition at line 407 of file BDBleApiImpl.java.

@@ -1752,7 +1784,7 @@

-

Definition at line 1042 of file BDBleApiImpl.java.

+

Definition at line 1047 of file BDBleApiImpl.java.

@@ -1780,7 +1812,7 @@

-

Definition at line 1072 of file BDBleApiImpl.java.

+

Definition at line 1077 of file BDBleApiImpl.java.

@@ -1824,7 +1856,7 @@

-

Definition at line 886 of file BDBleApiImpl.java.

+

Definition at line 891 of file BDBleApiImpl.java.

@@ -1852,7 +1884,7 @@

-

Definition at line 427 of file BDBleApiImpl.java.

+

Definition at line 432 of file BDBleApiImpl.java.

diff --git a/polar-sdk-android/docs/html/classpolar_1_1com_1_1sdk_1_1impl_1_1BDBleApiImpl.js b/polar-sdk-android/docs/html/classpolar_1_1com_1_1sdk_1_1impl_1_1BDBleApiImpl.js index e3cd7dba..ebdacbc2 100644 --- a/polar-sdk-android/docs/html/classpolar_1_1com_1_1sdk_1_1impl_1_1BDBleApiImpl.js +++ b/polar-sdk-android/docs/html/classpolar_1_1com_1_1sdk_1_1impl_1_1BDBleApiImpl.js @@ -34,6 +34,7 @@ var classpolar_1_1com_1_1sdk_1_1impl_1_1BDBleApiImpl = [ "setApiLogger", "classpolar_1_1com_1_1sdk_1_1impl_1_1BDBleApiImpl.html#ad239df6d03a59f3a85506346931b52a1", null ], [ "setAutomaticReconnection", "classpolar_1_1com_1_1sdk_1_1impl_1_1BDBleApiImpl.html#a2c36d4ab6fbdc804df500d2a1d1c0e5d", null ], [ "setLocalTime", "classpolar_1_1com_1_1sdk_1_1impl_1_1BDBleApiImpl.html#a95d10bce5ba70d0b499f610d761aeabb", null ], + [ "setMtu", "classpolar_1_1com_1_1sdk_1_1impl_1_1BDBleApiImpl.html#a5f47612ad1d1171257ce7365c676ad09", null ], [ "setPolarFilter", "classpolar_1_1com_1_1sdk_1_1impl_1_1BDBleApiImpl.html#ac08c2703034dc62317eaa6c47ed2284c", null ], [ "setupDevice", "classpolar_1_1com_1_1sdk_1_1impl_1_1BDBleApiImpl.html#a4a711dc98144cb480f5b4e4ef3c2af5b", null ], [ "shutDown", "classpolar_1_1com_1_1sdk_1_1impl_1_1BDBleApiImpl.html#ae1296701871fe33af919ca9423cadd7a", null ], diff --git a/polar-sdk-android/docs/html/functions.html b/polar-sdk-android/docs/html/functions.html index 2fb98d0d..d0473534 100644 --- a/polar-sdk-android/docs/html/functions.html +++ b/polar-sdk-android/docs/html/functions.html @@ -485,6 +485,10 @@

- s -

    : polar.com.sdk.api.PolarBleApi , polar.com.sdk.impl.BDBleApiImpl +
  • setMtu() +: polar.com.sdk.api.PolarBleApi +, polar.com.sdk.impl.BDBleApiImpl +
  • setPolarFilter() : polar.com.sdk.api.PolarBleApi , polar.com.sdk.impl.BDBleApiImpl diff --git a/polar-sdk-android/docs/html/functions_func.html b/polar-sdk-android/docs/html/functions_func.html index 37379e10..fc7c389d 100644 --- a/polar-sdk-android/docs/html/functions_func.html +++ b/polar-sdk-android/docs/html/functions_func.html @@ -356,6 +356,10 @@

    - s -

      : polar.com.sdk.api.PolarBleApi , polar.com.sdk.impl.BDBleApiImpl +
    • setMtu() +: polar.com.sdk.api.PolarBleApi +, polar.com.sdk.impl.BDBleApiImpl +
    • setPolarFilter() : polar.com.sdk.api.PolarBleApi , polar.com.sdk.impl.BDBleApiImpl diff --git a/polar-sdk-android/docs/html/navtreedata.js b/polar-sdk-android/docs/html/navtreedata.js index 4be222b1..a9f4f5f3 100644 --- a/polar-sdk-android/docs/html/navtreedata.js +++ b/polar-sdk-android/docs/html/navtreedata.js @@ -46,7 +46,7 @@ var NAVTREE = var NAVTREEINDEX = [ "BDBleApiImpl_8java.html", -"interfacepolar_1_1com_1_1sdk_1_1api_1_1PolarBleApiCallbackProvider.html#a8a037114fa4c5a7c78960e66ae1c0b7c" +"interfacepolar_1_1com_1_1sdk_1_1api_1_1PolarBleApiCallbackProvider.html#a78097d3ec0e9008595d905ab2302d404" ]; var SYNCONMSG = 'click to disable panel synchronisation'; diff --git a/polar-sdk-android/docs/html/navtreeindex0.js b/polar-sdk-android/docs/html/navtreeindex0.js index b9dc6ef2..99a1f5e9 100644 --- a/polar-sdk-android/docs/html/navtreeindex0.js +++ b/polar-sdk-android/docs/html/navtreeindex0.js @@ -50,38 +50,39 @@ var NAVTREEINDEX0 = "classes.html":[1,1], "classpolar_1_1com_1_1sdk_1_1api_1_1PolarBleApi.html":[1,0,0,0,0,0,2], "classpolar_1_1com_1_1sdk_1_1api_1_1PolarBleApi.html#a08884e4115932e7917d190daf15ddff1":[1,0,0,0,0,0,2,15], -"classpolar_1_1com_1_1sdk_1_1api_1_1PolarBleApi.html#a11aa139fffa100c346c13a23fdedfe71":[1,0,0,0,0,0,2,27], -"classpolar_1_1com_1_1sdk_1_1api_1_1PolarBleApi.html#a20700bbdf15b3ea25c632814d3bde8a2":[1,0,0,0,0,0,2,33], -"classpolar_1_1com_1_1sdk_1_1api_1_1PolarBleApi.html#a24e95523c086c9c3818dabc81358d54c":[1,0,0,0,0,0,2,29], +"classpolar_1_1com_1_1sdk_1_1api_1_1PolarBleApi.html#a11aa139fffa100c346c13a23fdedfe71":[1,0,0,0,0,0,2,28], +"classpolar_1_1com_1_1sdk_1_1api_1_1PolarBleApi.html#a17372e01394efb53e7c8f83cb0e379eb":[1,0,0,0,0,0,2,25], +"classpolar_1_1com_1_1sdk_1_1api_1_1PolarBleApi.html#a20700bbdf15b3ea25c632814d3bde8a2":[1,0,0,0,0,0,2,34], +"classpolar_1_1com_1_1sdk_1_1api_1_1PolarBleApi.html#a24e95523c086c9c3818dabc81358d54c":[1,0,0,0,0,0,2,30], "classpolar_1_1com_1_1sdk_1_1api_1_1PolarBleApi.html#a2a6de926dbcc32299dd79d2ba88e2544":[1,0,0,0,0,0,2,9], "classpolar_1_1com_1_1sdk_1_1api_1_1PolarBleApi.html#a2f95d2c9b7c9963c3b7fa5d7c2949e43":[1,0,0,0,0,0,2,19], "classpolar_1_1com_1_1sdk_1_1api_1_1PolarBleApi.html#a32484f5b3bacdde45573298a4e1d12a5":[1,0,0,0,0,0,2,23], "classpolar_1_1com_1_1sdk_1_1api_1_1PolarBleApi.html#a352c7cf35ca7e19e891f4eb7c53940c0":[1,0,0,0,0,0,2,21], -"classpolar_1_1com_1_1sdk_1_1api_1_1PolarBleApi.html#a36bcd4eb256abc810de32d3dbdfdf9e2":[1,0,0,0,0,0,2,28], +"classpolar_1_1com_1_1sdk_1_1api_1_1PolarBleApi.html#a36bcd4eb256abc810de32d3dbdfdf9e2":[1,0,0,0,0,0,2,29], "classpolar_1_1com_1_1sdk_1_1api_1_1PolarBleApi.html#a3a0692503cb3f8ebd94bd393dd6b1a7b":[1,0,0,0,0,0,2,4], "classpolar_1_1com_1_1sdk_1_1api_1_1PolarBleApi.html#a43c533a7a7011c6d2f56a4497fae04f7":[1,0,0,0,0,0,2,7], "classpolar_1_1com_1_1sdk_1_1api_1_1PolarBleApi.html#a5397f7034f2f36820910b65d84b45b1c":[1,0,0,0,0,0,2,6], "classpolar_1_1com_1_1sdk_1_1api_1_1PolarBleApi.html#a551ad9f20c37fba8d7e1ad08c6c1b258":[1,0,0,0,0,0,2,12], "classpolar_1_1com_1_1sdk_1_1api_1_1PolarBleApi.html#a63713c5d8a89dee1d2e769068e803bed":[1,0,0,0,0,0,2,10], -"classpolar_1_1com_1_1sdk_1_1api_1_1PolarBleApi.html#a6b3b45f899b318df179c9779f9faaf48":[1,0,0,0,0,0,2,35], -"classpolar_1_1com_1_1sdk_1_1api_1_1PolarBleApi.html#a6cfd8b8ffa6ccf0a1763d54017825814":[1,0,0,0,0,0,2,30], -"classpolar_1_1com_1_1sdk_1_1api_1_1PolarBleApi.html#a72fb1fff72cefb0a594537439e77ce30":[1,0,0,0,0,0,2,31], +"classpolar_1_1com_1_1sdk_1_1api_1_1PolarBleApi.html#a6b3b45f899b318df179c9779f9faaf48":[1,0,0,0,0,0,2,36], +"classpolar_1_1com_1_1sdk_1_1api_1_1PolarBleApi.html#a6cfd8b8ffa6ccf0a1763d54017825814":[1,0,0,0,0,0,2,31], +"classpolar_1_1com_1_1sdk_1_1api_1_1PolarBleApi.html#a72fb1fff72cefb0a594537439e77ce30":[1,0,0,0,0,0,2,32], "classpolar_1_1com_1_1sdk_1_1api_1_1PolarBleApi.html#a8fadd778436185235f0d579077504d0b":[1,0,0,0,0,0,2,13], "classpolar_1_1com_1_1sdk_1_1api_1_1PolarBleApi.html#a914fe430c1ab1cd41f9a3ed72ccacda6":[1,0,0,0,0,0,2,14], "classpolar_1_1com_1_1sdk_1_1api_1_1PolarBleApi.html#aa29e34cea992198209979e5c780b0d81":[1,0,0,0,0,0,2,16], "classpolar_1_1com_1_1sdk_1_1api_1_1PolarBleApi.html#ab3027dbef46fdc8d3bc15348b494d6bc":[1,0,0,0,0,0,2,17], -"classpolar_1_1com_1_1sdk_1_1api_1_1PolarBleApi.html#ab6dec221f95ea5dce6118cadeb362006":[1,0,0,0,0,0,2,26], -"classpolar_1_1com_1_1sdk_1_1api_1_1PolarBleApi.html#ac2737c48f2aad83fd535d34134e43d17":[1,0,0,0,0,0,2,32], +"classpolar_1_1com_1_1sdk_1_1api_1_1PolarBleApi.html#ab6dec221f95ea5dce6118cadeb362006":[1,0,0,0,0,0,2,27], +"classpolar_1_1com_1_1sdk_1_1api_1_1PolarBleApi.html#ac2737c48f2aad83fd535d34134e43d17":[1,0,0,0,0,0,2,33], "classpolar_1_1com_1_1sdk_1_1api_1_1PolarBleApi.html#ac8923ad69235615e62262a25115a01b9":[1,0,0,0,0,0,2,24], "classpolar_1_1com_1_1sdk_1_1api_1_1PolarBleApi.html#ac92b34d91563bb7a208818dd4358b260":[1,0,0,0,0,0,2,22], "classpolar_1_1com_1_1sdk_1_1api_1_1PolarBleApi.html#acdbb4f7379e431ed53dec08e99657679":[1,0,0,0,0,0,2,20], "classpolar_1_1com_1_1sdk_1_1api_1_1PolarBleApi.html#ae34d02d96a9fac60edde6d7b3f61a2d5":[1,0,0,0,0,0,2,18], "classpolar_1_1com_1_1sdk_1_1api_1_1PolarBleApi.html#ae406adb00b8f13bcc7c4630b11628784":[1,0,0,0,0,0,2,5], -"classpolar_1_1com_1_1sdk_1_1api_1_1PolarBleApi.html#ae7a6e7c991db4f0fecca383e639cc74c":[1,0,0,0,0,0,2,25], +"classpolar_1_1com_1_1sdk_1_1api_1_1PolarBleApi.html#ae7a6e7c991db4f0fecca383e639cc74c":[1,0,0,0,0,0,2,26], "classpolar_1_1com_1_1sdk_1_1api_1_1PolarBleApi.html#aede0baa6824966c902f5981a3d2e3f72":[1,0,0,0,0,0,2,11], "classpolar_1_1com_1_1sdk_1_1api_1_1PolarBleApi.html#af5e518b8f1ef6ca3c4b1c95f16312b52":[1,0,0,0,0,0,2,8], "classpolar_1_1com_1_1sdk_1_1api_1_1PolarBleApi.html#afa663962cfcfa76ea7140315074ba39f":[1,0,0,0,0,0,2,3], -"classpolar_1_1com_1_1sdk_1_1api_1_1PolarBleApi.html#afe25cdd5414973383db68bffc75d492f":[1,0,0,0,0,0,2,34], +"classpolar_1_1com_1_1sdk_1_1api_1_1PolarBleApi.html#afe25cdd5414973383db68bffc75d492f":[1,0,0,0,0,0,2,35], "classpolar_1_1com_1_1sdk_1_1api_1_1PolarBleApiCallback.html":[1,0,0,0,0,0,3], "classpolar_1_1com_1_1sdk_1_1api_1_1PolarBleApiCallback.html#a2994bd2e8b3d80b4e4de9ad0bb0920e8":[1,0,0,0,0,0,3,0], "classpolar_1_1com_1_1sdk_1_1api_1_1PolarBleApiCallback.html#a2e4e8f71a75eebf87be49751fcf4b4e8":[1,0,0,0,0,0,3,3], @@ -167,55 +168,56 @@ var NAVTREEINDEX0 = "classpolar_1_1com_1_1sdk_1_1api_1_1model_1_1PolarSensorSetting.html#ac87c6566895707f999315d370a410bb2":[1,0,0,0,0,0,1,10,1], "classpolar_1_1com_1_1sdk_1_1api_1_1model_1_1PolarSensorSetting.html#ae59d938cc770438c06bbd16ea015c9ff":[1,0,0,0,0,0,1,10,5], "classpolar_1_1com_1_1sdk_1_1impl_1_1BDBleApiImpl.html":[1,0,0,0,0,1,0], -"classpolar_1_1com_1_1sdk_1_1impl_1_1BDBleApiImpl.html#a078b82465b26d7ba58637f2e58a2e4b7":[1,0,0,0,0,1,0,44], -"classpolar_1_1com_1_1sdk_1_1impl_1_1BDBleApiImpl.html#a1163224a654db6b5917ad81fc3aa2d23":[1,0,0,0,0,1,0,41], +"classpolar_1_1com_1_1sdk_1_1impl_1_1BDBleApiImpl.html#a078b82465b26d7ba58637f2e58a2e4b7":[1,0,0,0,0,1,0,45], +"classpolar_1_1com_1_1sdk_1_1impl_1_1BDBleApiImpl.html#a1163224a654db6b5917ad81fc3aa2d23":[1,0,0,0,0,1,0,42], "classpolar_1_1com_1_1sdk_1_1impl_1_1BDBleApiImpl.html#a1218a5c9c6a590b55f1d00c9a76d4a90":[1,0,0,0,0,1,0,11], -"classpolar_1_1com_1_1sdk_1_1impl_1_1BDBleApiImpl.html#a14a4d99e3a14c3e8dd2a9695e25ec9a8":[1,0,0,0,0,1,0,43], +"classpolar_1_1com_1_1sdk_1_1impl_1_1BDBleApiImpl.html#a14a4d99e3a14c3e8dd2a9695e25ec9a8":[1,0,0,0,0,1,0,44], "classpolar_1_1com_1_1sdk_1_1impl_1_1BDBleApiImpl.html#a24707fd78988e8b9f57d47a6d24cc7e3":[1,0,0,0,0,1,0,3], "classpolar_1_1com_1_1sdk_1_1impl_1_1BDBleApiImpl.html#a2c36d4ab6fbdc804df500d2a1d1c0e5d":[1,0,0,0,0,1,0,32], "classpolar_1_1com_1_1sdk_1_1impl_1_1BDBleApiImpl.html#a2ca3ebc9ca23822d2aca71a2002c1b73":[1,0,0,0,0,1,0,26], "classpolar_1_1com_1_1sdk_1_1impl_1_1BDBleApiImpl.html#a31b079f8337863ff89f6f1d6dbce65b9":[1,0,0,0,0,1,0,12], -"classpolar_1_1com_1_1sdk_1_1impl_1_1BDBleApiImpl.html#a34b010c3844f564a377bfb430170e4a9":[1,0,0,0,0,1,0,37], -"classpolar_1_1com_1_1sdk_1_1impl_1_1BDBleApiImpl.html#a3b89e047d30f1aea90be69a46cdd58d9":[1,0,0,0,0,1,0,49], +"classpolar_1_1com_1_1sdk_1_1impl_1_1BDBleApiImpl.html#a34b010c3844f564a377bfb430170e4a9":[1,0,0,0,0,1,0,38], +"classpolar_1_1com_1_1sdk_1_1impl_1_1BDBleApiImpl.html#a3b89e047d30f1aea90be69a46cdd58d9":[1,0,0,0,0,1,0,50], "classpolar_1_1com_1_1sdk_1_1impl_1_1BDBleApiImpl.html#a436696ba043d2a5d77d5fe33e2ab91cf":[1,0,0,0,0,1,0,24], "classpolar_1_1com_1_1sdk_1_1impl_1_1BDBleApiImpl.html#a49685140c9028f1d6f140977b03ab4ca":[1,0,0,0,0,1,0,0], -"classpolar_1_1com_1_1sdk_1_1impl_1_1BDBleApiImpl.html#a4a711dc98144cb480f5b4e4ef3c2af5b":[1,0,0,0,0,1,0,35], +"classpolar_1_1com_1_1sdk_1_1impl_1_1BDBleApiImpl.html#a4a711dc98144cb480f5b4e4ef3c2af5b":[1,0,0,0,0,1,0,36], "classpolar_1_1com_1_1sdk_1_1impl_1_1BDBleApiImpl.html#a4b83c6b87fbac8b7fae12f677aab7ff9":[1,0,0,0,0,1,0,6], -"classpolar_1_1com_1_1sdk_1_1impl_1_1BDBleApiImpl.html#a4eb11a28590fe41d76fdb88c28894ce2":[1,0,0,0,0,1,0,47], +"classpolar_1_1com_1_1sdk_1_1impl_1_1BDBleApiImpl.html#a4eb11a28590fe41d76fdb88c28894ce2":[1,0,0,0,0,1,0,48], "classpolar_1_1com_1_1sdk_1_1impl_1_1BDBleApiImpl.html#a4f3fceac06da15b3c1a39dc5bb7b80f1":[1,0,0,0,0,1,0,4], "classpolar_1_1com_1_1sdk_1_1impl_1_1BDBleApiImpl.html#a568cbfd6e9548d54fff470a938cbf000":[1,0,0,0,0,1,0,27], "classpolar_1_1com_1_1sdk_1_1impl_1_1BDBleApiImpl.html#a573753301ab6af12467792bc87fc19a2":[1,0,0,0,0,1,0,8], "classpolar_1_1com_1_1sdk_1_1impl_1_1BDBleApiImpl.html#a59c11713e724352b7a8356089185fbda":[1,0,0,0,0,1,0,1], -"classpolar_1_1com_1_1sdk_1_1impl_1_1BDBleApiImpl.html#a5d33c2910d8f2583ee44962c4bcac2bf":[1,0,0,0,0,1,0,42], -"classpolar_1_1com_1_1sdk_1_1impl_1_1BDBleApiImpl.html#a5e80e959cbc19490c9a1963e6914a092":[1,0,0,0,0,1,0,46], +"classpolar_1_1com_1_1sdk_1_1impl_1_1BDBleApiImpl.html#a5d33c2910d8f2583ee44962c4bcac2bf":[1,0,0,0,0,1,0,43], +"classpolar_1_1com_1_1sdk_1_1impl_1_1BDBleApiImpl.html#a5e80e959cbc19490c9a1963e6914a092":[1,0,0,0,0,1,0,47], +"classpolar_1_1com_1_1sdk_1_1impl_1_1BDBleApiImpl.html#a5f47612ad1d1171257ce7365c676ad09":[1,0,0,0,0,1,0,34], "classpolar_1_1com_1_1sdk_1_1impl_1_1BDBleApiImpl.html#a6170765b10eb5ecc9b6b9584b350fb1a":[1,0,0,0,0,1,0,15], "classpolar_1_1com_1_1sdk_1_1impl_1_1BDBleApiImpl.html#a647db72c6f3a1cbd7587cac769cf0e2c":[1,0,0,0,0,1,0,29], "classpolar_1_1com_1_1sdk_1_1impl_1_1BDBleApiImpl.html#a69edf9c785075d164e3c248192446f15":[1,0,0,0,0,1,0,23], "classpolar_1_1com_1_1sdk_1_1impl_1_1BDBleApiImpl.html#a74af3feec0f83aa5acb8846dc2a1d1d6":[1,0,0,0,0,1,0,30], -"classpolar_1_1com_1_1sdk_1_1impl_1_1BDBleApiImpl.html#a7700f8c34663e4f37e208c0b5c779582":[1,0,0,0,0,1,0,39], +"classpolar_1_1com_1_1sdk_1_1impl_1_1BDBleApiImpl.html#a7700f8c34663e4f37e208c0b5c779582":[1,0,0,0,0,1,0,40], "classpolar_1_1com_1_1sdk_1_1impl_1_1BDBleApiImpl.html#a829ace600b46dbcb598683a488f821b9":[1,0,0,0,0,1,0,10], "classpolar_1_1com_1_1sdk_1_1impl_1_1BDBleApiImpl.html#a8bdd3c4c4bc2c98a5ff9ac7cd1385948":[1,0,0,0,0,1,0,19], "classpolar_1_1com_1_1sdk_1_1impl_1_1BDBleApiImpl.html#a92ce7a49c8c5dda100c4095d96c2500d":[1,0,0,0,0,1,0,5], "classpolar_1_1com_1_1sdk_1_1impl_1_1BDBleApiImpl.html#a95d10bce5ba70d0b499f610d761aeabb":[1,0,0,0,0,1,0,33], -"classpolar_1_1com_1_1sdk_1_1impl_1_1BDBleApiImpl.html#a9863d8f3a3756b95cf030e821af4c21c":[1,0,0,0,0,1,0,38], +"classpolar_1_1com_1_1sdk_1_1impl_1_1BDBleApiImpl.html#a9863d8f3a3756b95cf030e821af4c21c":[1,0,0,0,0,1,0,39], "classpolar_1_1com_1_1sdk_1_1impl_1_1BDBleApiImpl.html#aa65443950ef837c869eb6199a643487c":[1,0,0,0,0,1,0,22], "classpolar_1_1com_1_1sdk_1_1impl_1_1BDBleApiImpl.html#aa7b05d48c5f57c4d66f1e1c182883739":[1,0,0,0,0,1,0,14], "classpolar_1_1com_1_1sdk_1_1impl_1_1BDBleApiImpl.html#aae9728d213d59602f3c74b447c83c136":[1,0,0,0,0,1,0,9], -"classpolar_1_1com_1_1sdk_1_1impl_1_1BDBleApiImpl.html#ab341f795ecc7020448e0be59b044d38d":[1,0,0,0,0,1,0,45], +"classpolar_1_1com_1_1sdk_1_1impl_1_1BDBleApiImpl.html#ab341f795ecc7020448e0be59b044d38d":[1,0,0,0,0,1,0,46], "classpolar_1_1com_1_1sdk_1_1impl_1_1BDBleApiImpl.html#ab7e325a9ea06accea9746866d0118f1b":[1,0,0,0,0,1,0,2], -"classpolar_1_1com_1_1sdk_1_1impl_1_1BDBleApiImpl.html#abb45392febb6f61abfe49ef9482f07bb":[1,0,0,0,0,1,0,51], +"classpolar_1_1com_1_1sdk_1_1impl_1_1BDBleApiImpl.html#abb45392febb6f61abfe49ef9482f07bb":[1,0,0,0,0,1,0,52], "classpolar_1_1com_1_1sdk_1_1impl_1_1BDBleApiImpl.html#abc85de0575973be85cc572460952b5d3":[1,0,0,0,0,1,0,21], -"classpolar_1_1com_1_1sdk_1_1impl_1_1BDBleApiImpl.html#ac08998b625def30d377e05abb8a80f8d":[1,0,0,0,0,1,0,50], -"classpolar_1_1com_1_1sdk_1_1impl_1_1BDBleApiImpl.html#ac08c2703034dc62317eaa6c47ed2284c":[1,0,0,0,0,1,0,34], +"classpolar_1_1com_1_1sdk_1_1impl_1_1BDBleApiImpl.html#ac08998b625def30d377e05abb8a80f8d":[1,0,0,0,0,1,0,51], +"classpolar_1_1com_1_1sdk_1_1impl_1_1BDBleApiImpl.html#ac08c2703034dc62317eaa6c47ed2284c":[1,0,0,0,0,1,0,35], "classpolar_1_1com_1_1sdk_1_1impl_1_1BDBleApiImpl.html#ac645b2eedd096132b613ed5c0b6ecc2f":[1,0,0,0,0,1,0,18], "classpolar_1_1com_1_1sdk_1_1impl_1_1BDBleApiImpl.html#ad239df6d03a59f3a85506346931b52a1":[1,0,0,0,0,1,0,31], "classpolar_1_1com_1_1sdk_1_1impl_1_1BDBleApiImpl.html#ae0186ce1014ad60295930835b3620a22":[1,0,0,0,0,1,0,25], -"classpolar_1_1com_1_1sdk_1_1impl_1_1BDBleApiImpl.html#ae1296701871fe33af919ca9423cadd7a":[1,0,0,0,0,1,0,36], -"classpolar_1_1com_1_1sdk_1_1impl_1_1BDBleApiImpl.html#ae46e26479d9e1d5c57605c97343fd0f4":[1,0,0,0,0,1,0,52], -"classpolar_1_1com_1_1sdk_1_1impl_1_1BDBleApiImpl.html#ae49061dfea23ddf3c13917f9c757d1f2":[1,0,0,0,0,1,0,48], +"classpolar_1_1com_1_1sdk_1_1impl_1_1BDBleApiImpl.html#ae1296701871fe33af919ca9423cadd7a":[1,0,0,0,0,1,0,37], +"classpolar_1_1com_1_1sdk_1_1impl_1_1BDBleApiImpl.html#ae46e26479d9e1d5c57605c97343fd0f4":[1,0,0,0,0,1,0,53], +"classpolar_1_1com_1_1sdk_1_1impl_1_1BDBleApiImpl.html#ae49061dfea23ddf3c13917f9c757d1f2":[1,0,0,0,0,1,0,49], "classpolar_1_1com_1_1sdk_1_1impl_1_1BDBleApiImpl.html#ae897ee6968f1b84641861cda05859a6a":[1,0,0,0,0,1,0,16], "classpolar_1_1com_1_1sdk_1_1impl_1_1BDBleApiImpl.html#aea179b27f1dc4b7ed1ad3e2cb971a7a8":[1,0,0,0,0,1,0,7], -"classpolar_1_1com_1_1sdk_1_1impl_1_1BDBleApiImpl.html#aed55c3ce811dbb765d761f3b90b8ff96":[1,0,0,0,0,1,0,40], +"classpolar_1_1com_1_1sdk_1_1impl_1_1BDBleApiImpl.html#aed55c3ce811dbb765d761f3b90b8ff96":[1,0,0,0,0,1,0,41], "classpolar_1_1com_1_1sdk_1_1impl_1_1BDBleApiImpl.html#aed83b0c4e2180511a242f1ccedd3d03c":[1,0,0,0,0,1,0,28], "classpolar_1_1com_1_1sdk_1_1impl_1_1BDBleApiImpl.html#af300d862a83d6f973d78081cde32ab99":[1,0,0,0,0,1,0,13], "classpolar_1_1com_1_1sdk_1_1impl_1_1BDBleApiImpl.html#af7371642d2f1d673a4d20fd05be9e983":[1,0,0,0,0,1,0,17], @@ -247,7 +249,5 @@ var NAVTREEINDEX0 = "interfacepolar_1_1com_1_1sdk_1_1api_1_1PolarBleApiCallbackProvider.html#a209adefc35b35bdcc47d4a3d18d3c612":[1,0,0,0,0,0,4,5], "interfacepolar_1_1com_1_1sdk_1_1api_1_1PolarBleApiCallbackProvider.html#a486c58d7f53d93646e73350b18ca7848":[1,0,0,0,0,0,4,10], "interfacepolar_1_1com_1_1sdk_1_1api_1_1PolarBleApiCallbackProvider.html#a4a24d6676e3d29a8351f1c81ca40643d":[1,0,0,0,0,0,4,13], -"interfacepolar_1_1com_1_1sdk_1_1api_1_1PolarBleApiCallbackProvider.html#a74443790ce843fc101418cda1bc34b96":[1,0,0,0,0,0,4,6], -"interfacepolar_1_1com_1_1sdk_1_1api_1_1PolarBleApiCallbackProvider.html#a78097d3ec0e9008595d905ab2302d404":[1,0,0,0,0,0,4,1], -"interfacepolar_1_1com_1_1sdk_1_1api_1_1PolarBleApiCallbackProvider.html#a85047da74eb267aff2bed4af4dd4b521":[1,0,0,0,0,0,4,0] +"interfacepolar_1_1com_1_1sdk_1_1api_1_1PolarBleApiCallbackProvider.html#a74443790ce843fc101418cda1bc34b96":[1,0,0,0,0,0,4,6] }; diff --git a/polar-sdk-android/docs/html/navtreeindex1.js b/polar-sdk-android/docs/html/navtreeindex1.js index a33a6766..f674752a 100644 --- a/polar-sdk-android/docs/html/navtreeindex1.js +++ b/polar-sdk-android/docs/html/navtreeindex1.js @@ -1,5 +1,7 @@ var NAVTREEINDEX1 = { +"interfacepolar_1_1com_1_1sdk_1_1api_1_1PolarBleApiCallbackProvider.html#a78097d3ec0e9008595d905ab2302d404":[1,0,0,0,0,0,4,1], +"interfacepolar_1_1com_1_1sdk_1_1api_1_1PolarBleApiCallbackProvider.html#a85047da74eb267aff2bed4af4dd4b521":[1,0,0,0,0,0,4,0], "interfacepolar_1_1com_1_1sdk_1_1api_1_1PolarBleApiCallbackProvider.html#a8a037114fa4c5a7c78960e66ae1c0b7c":[1,0,0,0,0,0,4,8], "interfacepolar_1_1com_1_1sdk_1_1api_1_1PolarBleApiCallbackProvider.html#a954feeb8cd34bdc09b695b4932c163cb":[1,0,0,0,0,0,4,7], "interfacepolar_1_1com_1_1sdk_1_1api_1_1PolarBleApiCallbackProvider.html#aa2327fad0fd836f18a3f26a6355a8d68":[1,0,0,0,0,0,4,3], @@ -9,20 +11,20 @@ var NAVTREEINDEX1 = "interfacepolar_1_1com_1_1sdk_1_1api_1_1PolarBleApiCallbackProvider.html#afa130881ddecbb8135bbf78dc45723ea":[1,0,0,0,0,0,4,4], "interfacepolar_1_1com_1_1sdk_1_1api_1_1PolarBleApi_1_1PolarBleApiLogger.html":[1,0,0,0,0,0,2,0], "interfacepolar_1_1com_1_1sdk_1_1api_1_1PolarBleApi_1_1PolarBleApiLogger.html#ae55d724f7a34d52fab2f781993d4efcc":[1,0,0,0,0,0,2,0,0], -"namespacepolar.html":[0,0,0], "namespacepolar.html":[1,0,0], +"namespacepolar.html":[0,0,0], "namespacepolar_1_1com.html":[0,0,0,0], "namespacepolar_1_1com.html":[1,0,0,0], -"namespacepolar_1_1com_1_1sdk.html":[0,0,0,0,0], "namespacepolar_1_1com_1_1sdk.html":[1,0,0,0,0], +"namespacepolar_1_1com_1_1sdk.html":[0,0,0,0,0], "namespacepolar_1_1com_1_1sdk_1_1api.html":[0,0,0,0,0,0], "namespacepolar_1_1com_1_1sdk_1_1api.html":[1,0,0,0,0,0], -"namespacepolar_1_1com_1_1sdk_1_1api_1_1errors.html":[0,0,0,0,0,0,0], "namespacepolar_1_1com_1_1sdk_1_1api_1_1errors.html":[1,0,0,0,0,0,0], -"namespacepolar_1_1com_1_1sdk_1_1api_1_1model.html":[1,0,0,0,0,0,1], +"namespacepolar_1_1com_1_1sdk_1_1api_1_1errors.html":[0,0,0,0,0,0,0], "namespacepolar_1_1com_1_1sdk_1_1api_1_1model.html":[0,0,0,0,0,0,1], -"namespacepolar_1_1com_1_1sdk_1_1impl.html":[1,0,0,0,0,1], +"namespacepolar_1_1com_1_1sdk_1_1api_1_1model.html":[1,0,0,0,0,0,1], "namespacepolar_1_1com_1_1sdk_1_1impl.html":[0,0,0,0,0,1], +"namespacepolar_1_1com_1_1sdk_1_1impl.html":[1,0,0,0,0,1], "namespaces.html":[0,0], "pages.html":[] };