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

Member Function Documentation

- -

◆ autoConnectToPolarDevice() [1/2]

+ +

◆ autoConnectToDevice() [1/2]

@@ -229,11 +231,17 @@

- + + + + + + + @@ -264,7 +272,7 @@

-

Start connecting to a nearby Polar device. PolarBleApiCallback::polarDeviceConnected callback is invoked when connection to a nearby device is established.

Parameters
+

Start connecting to a nearby Polar device. PolarBleApiCallback::polarDeviceConnected callback is invoked when connection to a nearby device is established.

Parameters

abstract Completable polar.com.sdk.api.PolarBleApi.autoConnectToPolarDevice abstract Completable polar.com.sdk.api.PolarBleApi.autoConnectToDevice ( int  rssiLimit,
@Nullable String service,
@@ -277,8 +285,8 @@

-

◆ autoConnectToPolarDevice() [2/2]

+ +

◆ autoConnectToDevice() [2/2]

@@ -287,11 +295,17 @@

rssiLimitRSSI (Received Signal Strength Indication) value is typically from -40 to -60 (dBm), depends on the used Bluetooth chipset and/or antenna tuning
timeoutmin time to search nearby device default = 2s
- + + + + + + + @@ -365,8 +379,8 @@

-

◆ connectToPolarDevice()

+ +

◆ connectToDevice()

@@ -375,7 +389,7 @@

abstract Completable polar.com.sdk.api.PolarBleApi.autoConnectToPolarDevice abstract Completable polar.com.sdk.api.PolarBleApi.autoConnectToDevice ( int  rssiLimit,
@Nullable String service,
- + @@ -388,17 +402,17 @@

-

Request a connection to a Polar device. Invokes PolarBleApiCallback::polarDeviceConnected callback.

Parameters
+

Request a connection to a Polar device. Invokes PolarBleApiCallback::polarDeviceConnected callback.

Parameters

abstract void polar.com.sdk.api.PolarBleApi.connectToPolarDevice abstract void polar.com.sdk.api.PolarBleApi.connectToDevice ( @NonNull final String  identifier)
- +
identifierPolar device id found printed on the sensor/device
identifierPolar device id found printed on the sensor/device or bt address

- -

◆ disconnectFromPolarDevice()

+ +

◆ disconnectFromDevice()

@@ -407,7 +421,7 @@

- + @@ -420,9 +434,9 @@

-

Request disconnecting from a Polar device. Invokes PolarBleApiCallback::polarDeviceDisconnected callback.

Parameters
+

Request disconnecting from a Polar device. Invokes PolarBleApiCallback::polarDeviceDisconnected callback.

Parameters

abstract void polar.com.sdk.api.PolarBleApi.disconnectFromPolarDevice abstract void polar.com.sdk.api.PolarBleApi.disconnectFromDevice ( @NonNull final String  identifier)
- +
identifierPolar device id found printed on the sensor/device
identifierPolar device id found printed on the sensor/device or bt address
@@ -464,7 +478,7 @@

Fetch single exercise data requires feature PolarBleApi::FEATURE_POLAR_FILE_TRANSFER

Parameters
- +
identifierPolar device id found printed on the sensor/device
identifierPolar device id found printed on the sensor/device or bt address
entryPolarExerciseEntry object
@@ -535,7 +549,7 @@

Parameters
- +
deviceIdpolar device id
deviceIdpolar device id or bt address
featurefeature to be requested
@@ -569,7 +583,7 @@

List all exercises stored in the device OH1/H10 requires feature PolarBleApi::FEATURE_POLAR_FILE_TRANSFER

Parameters
- +
identifierPolar device id found printed on the sensor/device
identifierPolar device id found printed on the sensor/device or bt address
@@ -613,7 +627,7 @@

Request to remove single exercise requires feature PolarBleApi::FEATURE_POLAR_FILE_TRANSFER

Parameters
- +
identifierPolar device id
identifierPolar device id found printed on the sensor/device or bt address
entryentry to be removed
@@ -647,7 +661,7 @@

request available acc settings requires feature PolarBleApi::FEATURE_POLAR_SENSOR_STREAMING

Parameters
- +
identifierpolar device id
identifierpolar device id or bt address
@@ -706,7 +720,7 @@

request available ecg settings requires feature PolarBleApi::FEATURE_POLAR_SENSOR_STREAMING

Parameters
- +
identifierpolar device id
identifierpolar device id or bt address
@@ -739,7 +753,7 @@

request available ppg settings requires feature PolarBleApi::FEATURE_POLAR_SENSOR_STREAMING

Parameters
- +
identifierpolar device id
identifierpolar device id or bt address
@@ -772,7 +786,7 @@

request current recording status only supported by H10, requires feature PolarBleApi::FEATURE_POLAR_FILE_TRANSFER

Parameters
- +
identifierpolar device id
identifierpolar device id or bt address
@@ -942,13 +956,45 @@

set time to device affects on sensor data stream(s) timestamps requires feature PolarBleApi::FEATURE_POLAR_FILE_TRANSFER

Parameters
- +
identifierpolar device id
identifierpolar device id or bt address
calendartime to set
Returns
Completable stream
+

+
+ +

◆ setPolarFilter()

+ +
+
+ + + + + +
+ + + + + + + + +
abstract void polar.com.sdk.api.PolarBleApi.setPolarFilter (boolean enable)
+
+abstract
+
+
Parameters
+ + +
enablefalse disable polar filter which means in all apis identifier can be bt address too
+
+
+
@@ -1012,7 +1058,7 @@

Start ACC (Accelerometer) stream. Stops ACC stream if the connection is closed, error occured during start or stream is disposed. Requires feature PolarBleApi::FEATURE_POLAR_SENSOR_STREAMING. Query available settings before stream start PolarBleApi::requestAccSettings

Parameters
- +
identifierPolar device id
identifierPolar device id found printed on the sensor/device or bt address
sensorSettingsettings to be used to start streaming
@@ -1098,7 +1144,7 @@

Start the ECG (Electrocardiography) stream. Stops the ECG stream if the connection is closed, error occured during start or stream is disposed. Requires feature PolarBleApi::FEATURE_POLAR_SENSOR_STREAMING. Query available settings before stream start PolarBleApi::requestEcgSettings

Parameters
- +
identifierPolar device id
identifierPolar device id found printed on the sensor/device or bt address
sensorSettingsettings to be used to start streaming
@@ -1184,7 +1230,7 @@

Start OHR (Optical heart rate) PPG (Photoplethysmography) stream. Stops PPG stream if the connection is closed, error occured during start or stream is disposed. Requires feature PolarBleApi::FEATURE_POLAR_SENSOR_STREAMING. Query available settings before stream start PolarBleApi::requestPpgSettings

Parameters
- +
identifierPolar device id
identifierPolar device id found printed on the sensor/device or bt address
sensorSettingsettings to be used to start streaming
@@ -1224,7 +1270,7 @@

Start OHR (Optical heart rate) PPI (Pulse to Pulse interval) stream. Notice that there is a delay before PPI data stream starts Requires feature PolarBleApi::FEATURE_POLAR_SENSOR_STREAMING.

Parameters
- +
identifierPolar device id
identifierPolar device id found printed on the sensor/device or bt address
@@ -1285,7 +1331,7 @@

request start recording only supported by H10, requires feature PolarBleApi::FEATURE_POLAR_FILE_TRANSFER

Parameters
- + @@ -1321,7 +1367,7 @@

request stop recording only supported by H10, requires feature PolarBleApi::FEATURE_POLAR_FILE_TRANSFER

Parameters

identifierpolar device id
identifierpolar device id or bt address
exerciseIdunique id for exercise entry
intervalrecording interval to be used
typesample type to be used
- +
identifierpolar device id
identifierpolar device id or bt address
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 ce682ea5..4525f294 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 @@ -4,12 +4,12 @@ var classpolar_1_1com_1_1sdk_1_1api_1_1PolarBleApi = [ "RecordingInterval", "enumpolar_1_1com_1_1sdk_1_1api_1_1PolarBleApi_1_1RecordingInterval.html", "enumpolar_1_1com_1_1sdk_1_1api_1_1PolarBleApi_1_1RecordingInterval" ], [ "SampleType", "enumpolar_1_1com_1_1sdk_1_1api_1_1PolarBleApi_1_1SampleType.html", "enumpolar_1_1com_1_1sdk_1_1api_1_1PolarBleApi_1_1SampleType" ], [ "PolarBleApi", "classpolar_1_1com_1_1sdk_1_1api_1_1PolarBleApi.html#afa663962cfcfa76ea7140315074ba39f", null ], - [ "autoConnectToPolarDevice", "classpolar_1_1com_1_1sdk_1_1api_1_1PolarBleApi.html#aed92cfd7807194a6a82d708bdee2a313", null ], - [ "autoConnectToPolarDevice", "classpolar_1_1com_1_1sdk_1_1api_1_1PolarBleApi.html#ab8f30183f9ee4d1a0cc229e06f4f5d5b", null ], + [ "autoConnectToDevice", "classpolar_1_1com_1_1sdk_1_1api_1_1PolarBleApi.html#a3a0692503cb3f8ebd94bd393dd6b1a7b", null ], + [ "autoConnectToDevice", "classpolar_1_1com_1_1sdk_1_1api_1_1PolarBleApi.html#ae406adb00b8f13bcc7c4630b11628784", null ], [ "backgroundEntered", "classpolar_1_1com_1_1sdk_1_1api_1_1PolarBleApi.html#a5397f7034f2f36820910b65d84b45b1c", null ], [ "cleanup", "classpolar_1_1com_1_1sdk_1_1api_1_1PolarBleApi.html#a43c533a7a7011c6d2f56a4497fae04f7", null ], - [ "connectToPolarDevice", "classpolar_1_1com_1_1sdk_1_1api_1_1PolarBleApi.html#a1d83a0eec58e4a36f095207dcee71a6c", null ], - [ "disconnectFromPolarDevice", "classpolar_1_1com_1_1sdk_1_1api_1_1PolarBleApi.html#a90a6c60c7f16506e93745cd4111a5b25", null ], + [ "connectToDevice", "classpolar_1_1com_1_1sdk_1_1api_1_1PolarBleApi.html#af5e518b8f1ef6ca3c4b1c95f16312b52", null ], + [ "disconnectFromDevice", "classpolar_1_1com_1_1sdk_1_1api_1_1PolarBleApi.html#a2a6de926dbcc32299dd79d2ba88e2544", null ], [ "fetchExercise", "classpolar_1_1com_1_1sdk_1_1api_1_1PolarBleApi.html#a63713c5d8a89dee1d2e769068e803bed", null ], [ "foregroundEntered", "classpolar_1_1com_1_1sdk_1_1api_1_1PolarBleApi.html#aede0baa6824966c902f5981a3d2e3f72", null ], [ "isFeatureReady", "classpolar_1_1com_1_1sdk_1_1api_1_1PolarBleApi.html#a551ad9f20c37fba8d7e1ad08c6c1b258", null ], @@ -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 ], + [ "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 ], [ "startBiozStreaming", "classpolar_1_1com_1_1sdk_1_1api_1_1PolarBleApi.html#a36bcd4eb256abc810de32d3dbdfdf9e2", null ], diff --git a/polar-sdk-android/docs/html/classpolar_1_1com_1_1sdk_1_1api_1_1model_1_1PolarDeviceInfo.html b/polar-sdk-android/docs/html/classpolar_1_1com_1_1sdk_1_1api_1_1model_1_1PolarDeviceInfo.html index 2735d3ba..8cccf0c1 100644 --- a/polar-sdk-android/docs/html/classpolar_1_1com_1_1sdk_1_1api_1_1model_1_1PolarDeviceInfo.html +++ b/polar-sdk-android/docs/html/classpolar_1_1com_1_1sdk_1_1api_1_1model_1_1PolarDeviceInfo.html @@ -87,9 +87,9 @@  

Detailed Description

-

Contains information about the current Polar device.

+

Contains information about the current Device.

-

Definition at line 8 of file PolarDeviceInfo.java.

+

Definition at line 7 of file PolarDeviceInfo.java.

Constructor & Destructor Documentation

◆ PolarDeviceInfo()

@@ -137,7 +137,7 @@

-

Definition at line 30 of file PolarDeviceInfo.java.

+

Definition at line 29 of file PolarDeviceInfo.java.

@@ -153,9 +153,9 @@

-

Polar device id.

+

Polar device id or bt address.

-

Definition at line 13 of file PolarDeviceInfo.java.

+

Definition at line 12 of file PolarDeviceInfo.java.

@@ -172,7 +172,7 @@

true adv type is connectable

-

Definition at line 28 of file PolarDeviceInfo.java.

+

Definition at line 27 of file PolarDeviceInfo.java.

@@ -189,7 +189,7 @@

Device name.

-

Definition at line 23 of file PolarDeviceInfo.java.

+

Definition at line 22 of file PolarDeviceInfo.java.

@@ -206,7 +206,7 @@

Received signal strength indication value in dBm.

-

Definition at line 18 of file PolarDeviceInfo.java.

+

Definition at line 17 of file PolarDeviceInfo.java.

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 2c1665e0..24738ebc 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 @@ -65,9 +65,9 @@ +Protected Member Functions | +Protected Attributes | +Static Protected Attributes
polar.com.sdk.impl.BDBleApiImpl Class Reference
@@ -95,6 +95,8 @@   void cleanup ()   +void setPolarFilter (boolean enable) +  boolean isFeatureReady (final String deviceId, int feature)   void setApiCallback (PolarBleApiCallback callback) @@ -117,14 +119,14 @@   void foregroundEntered ()   -Completable autoConnectToPolarDevice (final int rssiLimit, final int timeout, final TimeUnit unit, final String polarDeviceType) -  -Completable autoConnectToPolarDevice (final int rssiLimit, final String polarDeviceType) -  -void connectToPolarDevice (final String identifier) -  -void disconnectFromPolarDevice (String identifier) -  +Completable autoConnectToDevice (final int rssiLimit, final String service, final int timeout, final TimeUnit unit, final String polarDeviceType) +  +Completable autoConnectToDevice (final int rssiLimit, final String service, final String polarDeviceType) +  +void connectToDevice (final String identifier) +  +void disconnectFromDevice (String identifier) +  Completable startRecording (String identifier, String exerciseId, RecordingInterval interval, SampleType type)   Completable stopRecording (String identifier) @@ -158,6 +160,8 @@   abstract void cleanup ()   +abstract void setPolarFilter (boolean enable) +  abstract boolean isFeatureReady (@NonNull final String deviceId, final int feature)   abstract void backgroundEntered () @@ -180,14 +184,14 @@   abstract Single< PolarSensorSettingrequestBiozSettings (@NonNull final String identifier)   -abstract Completable autoConnectToPolarDevice (int rssiLimit, int timeout, @NonNull TimeUnit unit, @Nullable final String polarDeviceType) -  -abstract Completable autoConnectToPolarDevice (int rssiLimit, final String polarDeviceType) -  -abstract void connectToPolarDevice (@NonNull final String identifier) -  -abstract void disconnectFromPolarDevice (@NonNull final String identifier) -  +abstract Completable autoConnectToDevice (int rssiLimit, @Nullable String service, int timeout, @NonNull TimeUnit unit, @Nullable final String polarDeviceType) +  +abstract Completable autoConnectToDevice (int rssiLimit, @Nullable String service, final String polarDeviceType) +  +abstract void connectToDevice (@NonNull final String identifier) +  +abstract void disconnectFromDevice (@NonNull final String identifier) +  abstract Completable startRecording (@NonNull final String identifier, @NonNull @Size(min=1, max=64) final String exerciseId, @NonNull RecordingInterval interval, @NonNull SampleType type)   abstract Completable stopRecording (@NonNull final String identifier) @@ -215,12 +219,16 @@ abstract Flowable< PolarOhrPPIDatastartOhrPPIStreaming (@NonNull final String identifier)   - + + + + + @@ -239,9 +247,12 @@ + + +

-Private Member Functions

+Protected Member Functions

void enableAndroidScanFilter ()
 
Single< PolarSensorSettingquerySettings (final String identifier, final BlePMDClient.PmdMeasurementType type)
 
BleDeviceSession fetchSession (final String identifier)
 
BleDeviceSession sessionByAddress (final String address)
 
BleDeviceSession sessionByDeviceId (final String deviceId)
 
BleDeviceSession sessionServiceReady (final String identifier, UUID service) throws Throwable
 
void logError (final String message)
 
- Protected Member Functions inherited from polar.com.sdk.api.PolarBleApi
 PolarBleApi (final int features)
 
- + @@ -252,9 +263,12 @@ + + +

-Private Attributes

+Protected Attributes

BleDeviceListener listener
 
Map< String, Disposable > connectSubscriptions = new HashMap<>()
 
PolarBleApiLogger logger
 
- Protected Attributes inherited from polar.com.sdk.api.PolarBleApi
int features
 
- + @@ -275,12 +289,6 @@ - - - - - -

-Static Private Attributes

+Static Protected Attributes

static final String TAG = BDBleApiImpl.class.getSimpleName()
 
static final int ANDROID_VERSION_O = 26
 
static final int ALL_FEATURES = 0xff
 
- Protected Member Functions inherited from polar.com.sdk.api.PolarBleApi
 PolarBleApi (final int features)
 
- Protected Attributes inherited from polar.com.sdk.api.PolarBleApi
int features
 

Detailed Description

The default implementation of the Polar API

@@ -321,13 +329,13 @@

-

Definition at line 101 of file BDBleApiImpl.java.

+

Definition at line 107 of file BDBleApiImpl.java.

Member Function Documentation

- -

◆ autoConnectToPolarDevice() [1/2]

+ +

◆ autoConnectToDevice() [1/2]

@@ -336,11 +344,17 @@

- + + + + + + + @@ -372,12 +386,12 @@

-

Definition at line 333 of file BDBleApiImpl.java.

+

Definition at line 344 of file BDBleApiImpl.java.

- -

◆ autoConnectToPolarDevice() [2/2]

+ +

◆ autoConnectToDevice() [2/2]

@@ -386,11 +400,17 @@

Completable polar.com.sdk.impl.BDBleApiImpl.autoConnectToPolarDevice Completable polar.com.sdk.impl.BDBleApiImpl.autoConnectToDevice ( final int  rssiLimit,
final String service,
- + + + + + + + @@ -410,7 +430,7 @@

-

Definition at line 378 of file BDBleApiImpl.java.

+

Definition at line 389 of file BDBleApiImpl.java.

@@ -437,7 +457,7 @@

-

Definition at line 323 of file BDBleApiImpl.java.

+

Definition at line 334 of file BDBleApiImpl.java.

@@ -464,12 +484,12 @@

-

Definition at line 231 of file BDBleApiImpl.java.

+

Definition at line 233 of file BDBleApiImpl.java.

- -

◆ connectToPolarDevice()

+ +

◆ connectToDevice()

@@ -478,7 +498,7 @@

Completable polar.com.sdk.impl.BDBleApiImpl.autoConnectToPolarDevice Completable polar.com.sdk.impl.BDBleApiImpl.autoConnectToDevice ( final int  rssiLimit,
final String service,
- + @@ -492,12 +512,12 @@

-

Definition at line 383 of file BDBleApiImpl.java.

+

Definition at line 394 of file BDBleApiImpl.java.

- -

◆ disconnectFromPolarDevice()

+ +

◆ disconnectFromDevice()

@@ -506,7 +526,7 @@

void polar.com.sdk.impl.BDBleApiImpl.connectToPolarDevice void polar.com.sdk.impl.BDBleApiImpl.connectToDevice ( final String  identifier)
- + @@ -520,7 +540,7 @@

-

Definition at line 418 of file BDBleApiImpl.java.

+

Definition at line 431 of file BDBleApiImpl.java.

@@ -542,12 +562,12 @@

-inlineprivate +inlineprotected

void polar.com.sdk.impl.BDBleApiImpl.disconnectFromPolarDevice void polar.com.sdk.impl.BDBleApiImpl.disconnectFromDevice ( String  identifier)

-

Definition at line 214 of file BDBleApiImpl.java.

+

Definition at line 216 of file BDBleApiImpl.java.

@@ -585,7 +605,7 @@

-

Definition at line 559 of file BDBleApiImpl.java.

+

Definition at line 572 of file BDBleApiImpl.java.

@@ -624,12 +644,40 @@

-inlineprivate +inlineprotected + + + + + +

◆ fetchSession()

+ +
+
+ + + +
+ + + + + + + + +
BleDeviceSession polar.com.sdk.impl.BDBleApiImpl.fetchSession (final String identifier)
+
+inlineprotected
-

Definition at line 1041 of file BDBleApiImpl.java.

+

Definition at line 841 of file BDBleApiImpl.java.

@@ -656,7 +704,7 @@

-

Definition at line 328 of file BDBleApiImpl.java.

+

Definition at line 339 of file BDBleApiImpl.java.

@@ -679,12 +727,12 @@

-inlineprivate +inlineprotected
-

Definition at line 1029 of file BDBleApiImpl.java.

+

Definition at line 1049 of file BDBleApiImpl.java.

@@ -722,7 +770,7 @@

-

Definition at line 236 of file BDBleApiImpl.java.

+

Definition at line 247 of file BDBleApiImpl.java.

@@ -750,7 +798,7 @@

-

Definition at line 503 of file BDBleApiImpl.java.

+

Definition at line 516 of file BDBleApiImpl.java.

@@ -773,12 +821,12 @@

-inlineprivate +inlineprotected
-

Definition at line 1073 of file BDBleApiImpl.java.

+

Definition at line 1093 of file BDBleApiImpl.java.

@@ -801,12 +849,12 @@

-inlineprivate +inlineprotected
-

Definition at line 1079 of file BDBleApiImpl.java.

+

Definition at line 1099 of file BDBleApiImpl.java.

@@ -839,12 +887,12 @@

-inlineprivate +inlineprotected
-

Definition at line 307 of file BDBleApiImpl.java.

+

Definition at line 318 of file BDBleApiImpl.java.

@@ -882,7 +930,7 @@

-

Definition at line 587 of file BDBleApiImpl.java.

+

Definition at line 600 of file BDBleApiImpl.java.

@@ -910,7 +958,7 @@

-

Definition at line 288 of file BDBleApiImpl.java.

+

Definition at line 299 of file BDBleApiImpl.java.

@@ -938,7 +986,7 @@

-

Definition at line 303 of file BDBleApiImpl.java.

+

Definition at line 314 of file BDBleApiImpl.java.

@@ -966,7 +1014,7 @@

-

Definition at line 293 of file BDBleApiImpl.java.

+

Definition at line 304 of file BDBleApiImpl.java.

@@ -994,7 +1042,7 @@

-

Definition at line 298 of file BDBleApiImpl.java.

+

Definition at line 309 of file BDBleApiImpl.java.

@@ -1022,7 +1070,7 @@

-

Definition at line 478 of file BDBleApiImpl.java.

+

Definition at line 491 of file BDBleApiImpl.java.

@@ -1049,7 +1097,35 @@

-

Definition at line 636 of file BDBleApiImpl.java.

+

Definition at line 649 of file BDBleApiImpl.java.

+ + + + +

◆ sessionByAddress()

+ +
+
+ + + + + +
+ + + + + + + + +
BleDeviceSession polar.com.sdk.impl.BDBleApiImpl.sessionByAddress (final String address)
+
+inlineprotected
+
+ +

Definition at line 845 of file BDBleApiImpl.java.

@@ -1072,12 +1148,12 @@

-inlineprivate +inlineprotected
-

Definition at line 829 of file BDBleApiImpl.java.

+

Definition at line 854 of file BDBleApiImpl.java.

@@ -1105,7 +1181,7 @@

-

Definition at line 853 of file BDBleApiImpl.java.

+

Definition at line 878 of file BDBleApiImpl.java.

@@ -1128,12 +1204,12 @@

-inlineprivate +inlineprotected
-

Definition at line 866 of file BDBleApiImpl.java.

+

Definition at line 891 of file BDBleApiImpl.java.

@@ -1166,12 +1242,12 @@

-inlineprivate +inlineprotected
-

Definition at line 838 of file BDBleApiImpl.java.

+

Definition at line 863 of file BDBleApiImpl.java.

@@ -1199,7 +1275,7 @@

-

Definition at line 250 of file BDBleApiImpl.java.

+

Definition at line 261 of file BDBleApiImpl.java.

@@ -1227,7 +1303,7 @@

-

Definition at line 256 of file BDBleApiImpl.java.

+

Definition at line 267 of file BDBleApiImpl.java.

@@ -1255,7 +1331,7 @@

-

Definition at line 261 of file BDBleApiImpl.java.

+

Definition at line 272 of file BDBleApiImpl.java.

@@ -1293,7 +1369,35 @@

-

Definition at line 266 of file BDBleApiImpl.java.

+

Definition at line 277 of file BDBleApiImpl.java.

+ + + + +

◆ setPolarFilter()

+ +
+
+ + + + + +
+ + + + + + + + +
void polar.com.sdk.impl.BDBleApiImpl.setPolarFilter (boolean enable)
+
+inline
+
+ +

Definition at line 238 of file BDBleApiImpl.java.

@@ -1316,12 +1420,12 @@

-inlineprivate +inlineprotected
-

Definition at line 898 of file BDBleApiImpl.java.

+

Definition at line 923 of file BDBleApiImpl.java.

@@ -1348,7 +1452,7 @@

-

Definition at line 226 of file BDBleApiImpl.java.

+

Definition at line 228 of file BDBleApiImpl.java.

@@ -1386,7 +1490,7 @@

-

Definition at line 703 of file BDBleApiImpl.java.

+

Definition at line 715 of file BDBleApiImpl.java.

@@ -1424,7 +1528,7 @@

-

Definition at line 803 of file BDBleApiImpl.java.

+

Definition at line 815 of file BDBleApiImpl.java.

@@ -1462,7 +1566,7 @@

-

Definition at line 671 of file BDBleApiImpl.java.

+

Definition at line 683 of file BDBleApiImpl.java.

@@ -1490,7 +1594,7 @@

-

Definition at line 651 of file BDBleApiImpl.java.

+

Definition at line 663 of file BDBleApiImpl.java.

@@ -1528,7 +1632,7 @@

-

Definition at line 735 of file BDBleApiImpl.java.

+

Definition at line 747 of file BDBleApiImpl.java.

@@ -1556,7 +1660,7 @@

-

Definition at line 767 of file BDBleApiImpl.java.

+

Definition at line 779 of file BDBleApiImpl.java.

@@ -1606,7 +1710,7 @@

-

Definition at line 434 of file BDBleApiImpl.java.

+

Definition at line 447 of file BDBleApiImpl.java.

@@ -1645,12 +1749,12 @@

-inlineprivate +inlineprotected
-

Definition at line 877 of file BDBleApiImpl.java.

+

Definition at line 902 of file BDBleApiImpl.java.

@@ -1678,7 +1782,7 @@

-

Definition at line 459 of file BDBleApiImpl.java.

+

Definition at line 472 of file BDBleApiImpl.java.

@@ -1698,7 +1802,7 @@

-staticprivate +staticprotected
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 456c251f..91ff9447 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 @@ -1,15 +1,16 @@ var classpolar_1_1com_1_1sdk_1_1impl_1_1BDBleApiImpl = [ [ "BDBleApiImpl", "classpolar_1_1com_1_1sdk_1_1impl_1_1BDBleApiImpl.html#a49685140c9028f1d6f140977b03ab4ca", null ], - [ "autoConnectToPolarDevice", "classpolar_1_1com_1_1sdk_1_1impl_1_1BDBleApiImpl.html#a964a35d7b8b782183fad03aae73b99be", null ], - [ "autoConnectToPolarDevice", "classpolar_1_1com_1_1sdk_1_1impl_1_1BDBleApiImpl.html#af8fe71975e2d06a5eac90781f5555d07", null ], + [ "autoConnectToDevice", "classpolar_1_1com_1_1sdk_1_1impl_1_1BDBleApiImpl.html#a59c11713e724352b7a8356089185fbda", null ], + [ "autoConnectToDevice", "classpolar_1_1com_1_1sdk_1_1impl_1_1BDBleApiImpl.html#ab7e325a9ea06accea9746866d0118f1b", null ], [ "backgroundEntered", "classpolar_1_1com_1_1sdk_1_1impl_1_1BDBleApiImpl.html#a24707fd78988e8b9f57d47a6d24cc7e3", null ], [ "cleanup", "classpolar_1_1com_1_1sdk_1_1impl_1_1BDBleApiImpl.html#a4f3fceac06da15b3c1a39dc5bb7b80f1", null ], - [ "connectToPolarDevice", "classpolar_1_1com_1_1sdk_1_1impl_1_1BDBleApiImpl.html#a4736cc12d728a7a8ddcd15a883486765", null ], - [ "disconnectFromPolarDevice", "classpolar_1_1com_1_1sdk_1_1impl_1_1BDBleApiImpl.html#a4d8a6d2fd920b9140d071db665aa762a", null ], + [ "connectToDevice", "classpolar_1_1com_1_1sdk_1_1impl_1_1BDBleApiImpl.html#a92ce7a49c8c5dda100c4095d96c2500d", null ], + [ "disconnectFromDevice", "classpolar_1_1com_1_1sdk_1_1impl_1_1BDBleApiImpl.html#a4b83c6b87fbac8b7fae12f677aab7ff9", null ], [ "enableAndroidScanFilter", "classpolar_1_1com_1_1sdk_1_1impl_1_1BDBleApiImpl.html#aea179b27f1dc4b7ed1ad3e2cb971a7a8", null ], [ "fetchExercise", "classpolar_1_1com_1_1sdk_1_1impl_1_1BDBleApiImpl.html#a573753301ab6af12467792bc87fc19a2", null ], [ "fetchRecursively", "classpolar_1_1com_1_1sdk_1_1impl_1_1BDBleApiImpl.html#aae9728d213d59602f3c74b447c83c136", null ], + [ "fetchSession", "classpolar_1_1com_1_1sdk_1_1impl_1_1BDBleApiImpl.html#a829ace600b46dbcb598683a488f821b9", null ], [ "foregroundEntered", "classpolar_1_1com_1_1sdk_1_1impl_1_1BDBleApiImpl.html#a1218a5c9c6a590b55f1d00c9a76d4a90", null ], [ "handleError", "classpolar_1_1com_1_1sdk_1_1impl_1_1BDBleApiImpl.html#a31b079f8337863ff89f6f1d6dbce65b9", null ], [ "isFeatureReady", "classpolar_1_1com_1_1sdk_1_1impl_1_1BDBleApiImpl.html#af300d862a83d6f973d78081cde32ab99", null ], @@ -24,6 +25,7 @@ var classpolar_1_1com_1_1sdk_1_1impl_1_1BDBleApiImpl = [ "requestPpgSettings", "classpolar_1_1com_1_1sdk_1_1impl_1_1BDBleApiImpl.html#aa65443950ef837c869eb6199a643487c", null ], [ "requestRecordingStatus", "classpolar_1_1com_1_1sdk_1_1impl_1_1BDBleApiImpl.html#aded82e5731dc626c167ea7437551ad6d", null ], [ "searchForPolarDevice", "classpolar_1_1com_1_1sdk_1_1impl_1_1BDBleApiImpl.html#a29b955b7813f2a1e6ebab906548964c8", null ], + [ "sessionByAddress", "classpolar_1_1com_1_1sdk_1_1impl_1_1BDBleApiImpl.html#ae0186ce1014ad60295930835b3620a22", null ], [ "sessionByDeviceId", "classpolar_1_1com_1_1sdk_1_1impl_1_1BDBleApiImpl.html#a2ca3ebc9ca23822d2aca71a2002c1b73", null ], [ "sessionPmdClientReady", "classpolar_1_1com_1_1sdk_1_1impl_1_1BDBleApiImpl.html#a568cbfd6e9548d54fff470a938cbf000", null ], [ "sessionPsFtpClientReady", "classpolar_1_1com_1_1sdk_1_1impl_1_1BDBleApiImpl.html#aed83b0c4e2180511a242f1ccedd3d03c", null ], @@ -32,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 ], + [ "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 ], [ "startAccStreaming", "classpolar_1_1com_1_1sdk_1_1impl_1_1BDBleApiImpl.html#a34b010c3844f564a377bfb430170e4a9", null ], diff --git a/polar-sdk-android/docs/html/functions.html b/polar-sdk-android/docs/html/functions.html index 1b83a4bf..892fb5ef 100644 --- a/polar-sdk-android/docs/html/functions.html +++ b/polar-sdk-android/docs/html/functions.html @@ -74,9 +74,9 @@

- a -

@@ -115,9 +115,9 @@

- c -

void blePowerStateChanged (final boolean powered)   -void polarDeviceConnected (@NonNull final PolarDeviceInfo polarDeviceInfo) -  -void polarDeviceConnecting (@NonNull final PolarDeviceInfo polarDeviceInfo) -  -void polarDeviceDisconnected (@NonNull final PolarDeviceInfo polarDeviceInfo) -  +void deviceConnected (@NonNull final PolarDeviceInfo polarDeviceInfo) +  +void deviceConnecting (@NonNull final PolarDeviceInfo polarDeviceInfo) +  +void deviceDisconnected (@NonNull final PolarDeviceInfo polarDeviceInfo) +  void ecgFeatureReady (@NonNull final String identifier)   void accelerometerFeatureReady (@NonNull final String identifier) @@ -91,8 +91,8 @@   void hrFeatureReady (@NonNull final String identifier)   -void fwInformationReceived (@NonNull final String identifier, @NonNull final String fwVersion) -  +void disInformationReceived (@NonNull final String identifier, @NonNull UUID uuid, @NonNull final String value) +  void batteryLevelReceived (@NonNull final String identifier, final int level)   void hrNotificationReceived (@NonNull final String identifier, @NonNull final PolarHrData data) @@ -103,7 +103,7 @@

Detailed Description

Contains the callbacks of the API.

-

Definition at line 11 of file PolarBleApiCallback.java.

+

Definition at line 13 of file PolarBleApiCallback.java.

Member Function Documentation

◆ accelerometerFeatureReady()

@@ -156,7 +156,7 @@

Battery level received requires feature PolarBleApi::FEATURE_BATTERY_INFO

Parameters
- +
identifierPolar device id
identifierPolar device id or bt address
levelbattery level (value between 0-100%)
@@ -212,97 +212,86 @@

-

◆ ecgFeatureReady()

+ +

◆ deviceConnected()

- + - - + +
void polar.com.sdk.api.PolarBleApiCallback.ecgFeatureReady void polar.com.sdk.api.PolarBleApiCallback.deviceConnected (@NonNull final String identifier)@NonNull final PolarDeviceInfo polarDeviceInfo)
-

Polar device's ECG feature is ready. Application may start ECG stream now if desired. requires feature PolarBleApi::FEATURE_POLAR_SENSOR_STREAMING

Parameters
+

Device is now connected

Parameters
- +
identifierPolar device id
polarDeviceInfoPolar device information
- -

◆ fwInformationReceived()

+ +

◆ deviceConnecting()

- + - - - - - + + - - - - - - -
void polar.com.sdk.api.PolarBleApiCallback.fwInformationReceived void polar.com.sdk.api.PolarBleApiCallback.deviceConnecting (@NonNull final String identifier,
@NonNull final PolarDeviceInfo polarDeviceInfo) @NonNull final String fwVersion 
)
-

Firmware version information received requires feature PolarBleApi::FEATURE_DEVICE_INFO

Parameters
+

Connecting to device

Parameters
- - +
identifierPolar device id
fwVersionversion in format major.minor.patch
polarDeviceInfoPolar device information
- -

◆ hrFeatureReady()

+ +

◆ deviceDisconnected()

- + - - + +
void polar.com.sdk.api.PolarBleApiCallback.hrFeatureReady void polar.com.sdk.api.PolarBleApiCallback.deviceDisconnected (@NonNull final String identifier)@NonNull final PolarDeviceInfo polarDeviceInfo)
-

Polar device HR client is now ready and HR transmission is starting in a moment.

Parameters
+

Device is now disconnected, no further action is needed from the application if polar.com.sdk.api.PolarBleApi::disconnectFromPolarDevice is not called. Device will be automatically reconnected

Parameters
- +
identifierPolar device id
polarDeviceInfoPolar device information
- -

◆ hrNotificationReceived()

+ +

◆ disInformationReceived()

- + @@ -310,8 +299,14 @@

- - + + + + + + + + @@ -320,86 +315,98 @@

-

HR notification data received from device

Parameters
+

DIS information received requires feature PolarBleApi::FEATURE_DEVICE_INFO

Parameters

void polar.com.sdk.api.PolarBleApiCallback.hrNotificationReceived void polar.com.sdk.api.PolarBleApiCallback.disInformationReceived ( @NonNull final String  identifier, @NonNull final PolarHrData data @NonNull UUID uuid,
@NonNull final String value 
- - + + +
identifierPolar device id
data
identifierPolar device id or bt address
uuiduuid of dis value
valuedis value for uuid

-
See also
polar.com.sdk.api.model.PolarHrData.java
- -

◆ polarDeviceConnected()

+ +

◆ ecgFeatureReady()

- + - - + +
void polar.com.sdk.api.PolarBleApiCallback.polarDeviceConnected void polar.com.sdk.api.PolarBleApiCallback.ecgFeatureReady (@NonNull final PolarDeviceInfo polarDeviceInfo)@NonNull final String identifier)
-

Polar device is now connected

Parameters
+

Polar device's ECG feature is ready. Application may start ECG stream now if desired. requires feature PolarBleApi::FEATURE_POLAR_SENSOR_STREAMING

Parameters
- +
polarDeviceInfoPolar device information
identifierPolar device id
- -

◆ polarDeviceConnecting()

+ +

◆ hrFeatureReady()

- + - - + +
void polar.com.sdk.api.PolarBleApiCallback.polarDeviceConnecting void polar.com.sdk.api.PolarBleApiCallback.hrFeatureReady (@NonNull final PolarDeviceInfo polarDeviceInfo)@NonNull final String identifier)
-

connecting to polar device

Parameters
+

Polar device HR client is now ready and HR transmission is starting in a moment.

Parameters
- +
polarDeviceInfoPolar device information
identifierPolar device id or bt address
- -

◆ polarDeviceDisconnected()

+ +

◆ hrNotificationReceived()

- + - - + + + + + + + + + + + +
void polar.com.sdk.api.PolarBleApiCallback.polarDeviceDisconnected void polar.com.sdk.api.PolarBleApiCallback.hrNotificationReceived (@NonNull final PolarDeviceInfo polarDeviceInfo)@NonNull final String identifier,
@NonNull final PolarHrData data 
)
-

Polar device is now disconnected, no further action is needed from the application if polar.com.sdk.api.PolarBleApi::disconnectFromPolarDevice is not called. Device will be automatically reconnected

Parameters
+

HR notification data received from device

Parameters
- + +
polarDeviceInfoPolar device information
identifierPolar device id or bt address
data
+
See also
polar.com.sdk.api.model.PolarHrData.java
diff --git a/polar-sdk-android/docs/html/interfacepolar_1_1com_1_1sdk_1_1api_1_1PolarBleApiCallback.js b/polar-sdk-android/docs/html/interfacepolar_1_1com_1_1sdk_1_1api_1_1PolarBleApiCallback.js index ab2d8baa..82d4a145 100644 --- a/polar-sdk-android/docs/html/interfacepolar_1_1com_1_1sdk_1_1api_1_1PolarBleApiCallback.js +++ b/polar-sdk-android/docs/html/interfacepolar_1_1com_1_1sdk_1_1api_1_1PolarBleApiCallback.js @@ -4,13 +4,13 @@ var interfacepolar_1_1com_1_1sdk_1_1api_1_1PolarBleApiCallback = [ "batteryLevelReceived", "interfacepolar_1_1com_1_1sdk_1_1api_1_1PolarBleApiCallback.html#ad98839ae9719804e7f93db93c03a3502", null ], [ "biozFeatureReady", "interfacepolar_1_1com_1_1sdk_1_1api_1_1PolarBleApiCallback.html#afec6d56715ba82b46129812be452f1ba", null ], [ "blePowerStateChanged", "interfacepolar_1_1com_1_1sdk_1_1api_1_1PolarBleApiCallback.html#a2e4e8f71a75eebf87be49751fcf4b4e8", null ], + [ "deviceConnected", "interfacepolar_1_1com_1_1sdk_1_1api_1_1PolarBleApiCallback.html#ae98b2e7a18f12255b955693e1afc7bf2", null ], + [ "deviceConnecting", "interfacepolar_1_1com_1_1sdk_1_1api_1_1PolarBleApiCallback.html#ab6b0fa75da852019c7b74820e00f2cb9", null ], + [ "deviceDisconnected", "interfacepolar_1_1com_1_1sdk_1_1api_1_1PolarBleApiCallback.html#a8d2b40c2a8b2b14d98778f7542e337b8", null ], + [ "disInformationReceived", "interfacepolar_1_1com_1_1sdk_1_1api_1_1PolarBleApiCallback.html#ae9028fa8d2b8a017db6c01d061a69c8e", null ], [ "ecgFeatureReady", "interfacepolar_1_1com_1_1sdk_1_1api_1_1PolarBleApiCallback.html#a3c2c3ff7eb76a8cba67057b60122b035", null ], - [ "fwInformationReceived", "interfacepolar_1_1com_1_1sdk_1_1api_1_1PolarBleApiCallback.html#a535f9cd51fed5b5cb942043491805fce", null ], [ "hrFeatureReady", "interfacepolar_1_1com_1_1sdk_1_1api_1_1PolarBleApiCallback.html#a60b5030d4ee50f7cf9d50bcbe2229808", null ], [ "hrNotificationReceived", "interfacepolar_1_1com_1_1sdk_1_1api_1_1PolarBleApiCallback.html#aa9534a4ec9f2269d19a112f54d2ec0e0", null ], - [ "polarDeviceConnected", "interfacepolar_1_1com_1_1sdk_1_1api_1_1PolarBleApiCallback.html#a2cb360c2635633d6e78affa9a19b71b9", null ], - [ "polarDeviceConnecting", "interfacepolar_1_1com_1_1sdk_1_1api_1_1PolarBleApiCallback.html#a4cceddbd2d8d2933893509f35d4cb4f9", null ], - [ "polarDeviceDisconnected", "interfacepolar_1_1com_1_1sdk_1_1api_1_1PolarBleApiCallback.html#a3ff1646ff47dcd2a3cc5df276c0d1f6d", null ], [ "polarFtpFeatureReady", "interfacepolar_1_1com_1_1sdk_1_1api_1_1PolarBleApiCallback.html#ad2055f89f0e3a0d1dfce7a444b507698", null ], [ "ppgFeatureReady", "interfacepolar_1_1com_1_1sdk_1_1api_1_1PolarBleApiCallback.html#a3541b2cec92744126a84ec207f3e1211", null ], [ "ppiFeatureReady", "interfacepolar_1_1com_1_1sdk_1_1api_1_1PolarBleApiCallback.html#af5ab3ec3f17b4f32085e9e085b0f38c3", null ] diff --git a/polar-sdk-android/docs/html/navtreeindex0.js b/polar-sdk-android/docs/html/navtreeindex0.js index c7fd23fa..f25a83b8 100644 --- a/polar-sdk-android/docs/html/navtreeindex0.js +++ b/polar-sdk-android/docs/html/navtreeindex0.js @@ -46,37 +46,38 @@ 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,26], +"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#a19008b45f93c7ef985a4e47df77674dc":[1,0,0,0,0,0,2,20], -"classpolar_1_1com_1_1sdk_1_1api_1_1PolarBleApi.html#a1d83a0eec58e4a36f095207dcee71a6c":[1,0,0,0,0,0,2,8], -"classpolar_1_1com_1_1sdk_1_1api_1_1PolarBleApi.html#a20700bbdf15b3ea25c632814d3bde8a2":[1,0,0,0,0,0,2,32], -"classpolar_1_1com_1_1sdk_1_1api_1_1PolarBleApi.html#a24e95523c086c9c3818dabc81358d54c":[1,0,0,0,0,0,2,28], +"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#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#a36bcd4eb256abc810de32d3dbdfdf9e2":[1,0,0,0,0,0,2,27], +"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#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#a4682d9318c9ac41927694421bde349a5":[1,0,0,0,0,0,2,21], "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,34], -"classpolar_1_1com_1_1sdk_1_1api_1_1PolarBleApi.html#a6cfd8b8ffa6ccf0a1763d54017825814":[1,0,0,0,0,0,2,29], -"classpolar_1_1com_1_1sdk_1_1api_1_1PolarBleApi.html#a72fb1fff72cefb0a594537439e77ce30":[1,0,0,0,0,0,2,30], +"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#a8fadd778436185235f0d579077504d0b":[1,0,0,0,0,0,2,13], -"classpolar_1_1com_1_1sdk_1_1api_1_1PolarBleApi.html#a90a6c60c7f16506e93745cd4111a5b25":[1,0,0,0,0,0,2,9], "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,25], -"classpolar_1_1com_1_1sdk_1_1api_1_1PolarBleApi.html#ab8f30183f9ee4d1a0cc229e06f4f5d5b":[1,0,0,0,0,0,2,5], -"classpolar_1_1com_1_1sdk_1_1api_1_1PolarBleApi.html#ac2737c48f2aad83fd535d34134e43d17":[1,0,0,0,0,0,2,31], +"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#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#ae34d02d96a9fac60edde6d7b3f61a2d5":[1,0,0,0,0,0,2,18], -"classpolar_1_1com_1_1sdk_1_1api_1_1PolarBleApi.html#aed92cfd7807194a6a82d708bdee2a313":[1,0,0,0,0,0,2,4], +"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#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,33], +"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_1PolarBleApiDefaultImpl.html":[1,0,0,0,0,0,4], "classpolar_1_1com_1_1sdk_1_1api_1_1errors_1_1PolarDeviceDisconnected.html":[1,0,0,0,0,0,0,0], "classpolar_1_1com_1_1sdk_1_1api_1_1errors_1_1PolarDeviceNotConnected.html":[1,0,0,0,0,0,0,1], @@ -140,54 +141,57 @@ 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#a1163224a654db6b5917ad81fc3aa2d23":[1,0,0,0,0,1,0,38], -"classpolar_1_1com_1_1sdk_1_1impl_1_1BDBleApiImpl.html#a1218a5c9c6a590b55f1d00c9a76d4a90":[1,0,0,0,0,1,0,10], -"classpolar_1_1com_1_1sdk_1_1impl_1_1BDBleApiImpl.html#a14a4d99e3a14c3e8dd2a9695e25ec9a8":[1,0,0,0,0,1,0,40], +"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#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#a24707fd78988e8b9f57d47a6d24cc7e3":[1,0,0,0,0,1,0,3], -"classpolar_1_1com_1_1sdk_1_1impl_1_1BDBleApiImpl.html#a29b955b7813f2a1e6ebab906548964c8":[1,0,0,0,0,1,0,23], -"classpolar_1_1com_1_1sdk_1_1impl_1_1BDBleApiImpl.html#a2c36d4ab6fbdc804df500d2a1d1c0e5d":[1,0,0,0,0,1,0,30], -"classpolar_1_1com_1_1sdk_1_1impl_1_1BDBleApiImpl.html#a2ca3ebc9ca23822d2aca71a2002c1b73":[1,0,0,0,0,1,0,24], -"classpolar_1_1com_1_1sdk_1_1impl_1_1BDBleApiImpl.html#a31b079f8337863ff89f6f1d6dbce65b9":[1,0,0,0,0,1,0,11], -"classpolar_1_1com_1_1sdk_1_1impl_1_1BDBleApiImpl.html#a34b010c3844f564a377bfb430170e4a9":[1,0,0,0,0,1,0,34], -"classpolar_1_1com_1_1sdk_1_1impl_1_1BDBleApiImpl.html#a4736cc12d728a7a8ddcd15a883486765":[1,0,0,0,0,1,0,5], +"classpolar_1_1com_1_1sdk_1_1impl_1_1BDBleApiImpl.html#a29b955b7813f2a1e6ebab906548964c8":[1,0,0,0,0,1,0,24], +"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#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,32], -"classpolar_1_1com_1_1sdk_1_1impl_1_1BDBleApiImpl.html#a4d8a6d2fd920b9140d071db665aa762a":[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,42], +"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#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,45], "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,25], +"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#a5ccfe3027f85d5b1262737b1160006b8":[1,0,0,0,0,1,0,43], -"classpolar_1_1com_1_1sdk_1_1impl_1_1BDBleApiImpl.html#a5d33c2910d8f2583ee44962c4bcac2bf":[1,0,0,0,0,1,0,39], -"classpolar_1_1com_1_1sdk_1_1impl_1_1BDBleApiImpl.html#a5e80e959cbc19490c9a1963e6914a092":[1,0,0,0,0,1,0,41], -"classpolar_1_1com_1_1sdk_1_1impl_1_1BDBleApiImpl.html#a6170765b10eb5ecc9b6b9584b350fb1a":[1,0,0,0,0,1,0,14], -"classpolar_1_1com_1_1sdk_1_1impl_1_1BDBleApiImpl.html#a647db72c6f3a1cbd7587cac769cf0e2c":[1,0,0,0,0,1,0,27], -"classpolar_1_1com_1_1sdk_1_1impl_1_1BDBleApiImpl.html#a7700f8c34663e4f37e208c0b5c779582":[1,0,0,0,0,1,0,36], -"classpolar_1_1com_1_1sdk_1_1impl_1_1BDBleApiImpl.html#a8bdd3c4c4bc2c98a5ff9ac7cd1385948":[1,0,0,0,0,1,0,18], -"classpolar_1_1com_1_1sdk_1_1impl_1_1BDBleApiImpl.html#a95d10bce5ba70d0b499f610d761aeabb":[1,0,0,0,0,1,0,31], -"classpolar_1_1com_1_1sdk_1_1impl_1_1BDBleApiImpl.html#a964a35d7b8b782183fad03aae73b99be":[1,0,0,0,0,1,0,1], -"classpolar_1_1com_1_1sdk_1_1impl_1_1BDBleApiImpl.html#a9863d8f3a3756b95cf030e821af4c21c":[1,0,0,0,0,1,0,35], -"classpolar_1_1com_1_1sdk_1_1impl_1_1BDBleApiImpl.html#aa65443950ef837c869eb6199a643487c":[1,0,0,0,0,1,0,21], -"classpolar_1_1com_1_1sdk_1_1impl_1_1BDBleApiImpl.html#aa7b05d48c5f57c4d66f1e1c182883739":[1,0,0,0,0,1,0,13], +"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#a5ccfe3027f85d5b1262737b1160006b8":[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,42], +"classpolar_1_1com_1_1sdk_1_1impl_1_1BDBleApiImpl.html#a5e80e959cbc19490c9a1963e6914a092":[1,0,0,0,0,1,0,44], +"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#a7700f8c34663e4f37e208c0b5c779582":[1,0,0,0,0,1,0,39], +"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#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#abb45392febb6f61abfe49ef9482f07bb":[1,0,0,0,0,1,0,46], -"classpolar_1_1com_1_1sdk_1_1impl_1_1BDBleApiImpl.html#abc85de0575973be85cc572460952b5d3":[1,0,0,0,0,1,0,20], -"classpolar_1_1com_1_1sdk_1_1impl_1_1BDBleApiImpl.html#ac08998b625def30d377e05abb8a80f8d":[1,0,0,0,0,1,0,45], -"classpolar_1_1com_1_1sdk_1_1impl_1_1BDBleApiImpl.html#ac61c2b578af2d5563ef677172196d04d":[1,0,0,0,0,1,0,28], -"classpolar_1_1com_1_1sdk_1_1impl_1_1BDBleApiImpl.html#ac645b2eedd096132b613ed5c0b6ecc2f":[1,0,0,0,0,1,0,17], -"classpolar_1_1com_1_1sdk_1_1impl_1_1BDBleApiImpl.html#ac6df07abc427e5ad2ba3167a2d8c109b":[1,0,0,0,0,1,0,44], -"classpolar_1_1com_1_1sdk_1_1impl_1_1BDBleApiImpl.html#ad239df6d03a59f3a85506346931b52a1":[1,0,0,0,0,1,0,29], -"classpolar_1_1com_1_1sdk_1_1impl_1_1BDBleApiImpl.html#aded82e5731dc626c167ea7437551ad6d":[1,0,0,0,0,1,0,22], -"classpolar_1_1com_1_1sdk_1_1impl_1_1BDBleApiImpl.html#ae1296701871fe33af919ca9423cadd7a":[1,0,0,0,0,1,0,33], -"classpolar_1_1com_1_1sdk_1_1impl_1_1BDBleApiImpl.html#ae46e26479d9e1d5c57605c97343fd0f4":[1,0,0,0,0,1,0,47], -"classpolar_1_1com_1_1sdk_1_1impl_1_1BDBleApiImpl.html#ae897ee6968f1b84641861cda05859a6a":[1,0,0,0,0,1,0,15], +"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,49], +"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,48], +"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#ac61c2b578af2d5563ef677172196d04d":[1,0,0,0,0,1,0,30], +"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#ac6df07abc427e5ad2ba3167a2d8c109b":[1,0,0,0,0,1,0,47], +"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#aded82e5731dc626c167ea7437551ad6d":[1,0,0,0,0,1,0,23], +"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,50], +"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,37], -"classpolar_1_1com_1_1sdk_1_1impl_1_1BDBleApiImpl.html#aed83b0c4e2180511a242f1ccedd3d03c":[1,0,0,0,0,1,0,26], -"classpolar_1_1com_1_1sdk_1_1impl_1_1BDBleApiImpl.html#af300d862a83d6f973d78081cde32ab99":[1,0,0,0,0,1,0,12], -"classpolar_1_1com_1_1sdk_1_1impl_1_1BDBleApiImpl.html#af7371642d2f1d673a4d20fd05be9e983":[1,0,0,0,0,1,0,16], -"classpolar_1_1com_1_1sdk_1_1impl_1_1BDBleApiImpl.html#af8fe71975e2d06a5eac90781f5555d07":[1,0,0,0,0,1,0,2], -"classpolar_1_1com_1_1sdk_1_1impl_1_1BDBleApiImpl.html#afc92150da6c98b93a9f86439a0d33e3d":[1,0,0,0,0,1,0,19], +"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#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], +"classpolar_1_1com_1_1sdk_1_1impl_1_1BDBleApiImpl.html#afc92150da6c98b93a9f86439a0d33e3d":[1,0,0,0,0,1,0,20], "enumpolar_1_1com_1_1sdk_1_1api_1_1PolarBleApi_1_1RecordingInterval.html":[1,0,0,0,0,0,2,1], "enumpolar_1_1com_1_1sdk_1_1api_1_1PolarBleApi_1_1RecordingInterval.html#a393dd3e19d57d5f0a9a256f275050f4b":[1,0,0,0,0,0,2,1,2], "enumpolar_1_1com_1_1sdk_1_1api_1_1PolarBleApi_1_1RecordingInterval.html#a4a931111cd9d6b0103000bbd7e9aee8a":[1,0,0,0,0,0,2,1,0], @@ -212,31 +216,31 @@ var NAVTREEINDEX0 = "index.html":[], "interfacepolar_1_1com_1_1sdk_1_1api_1_1PolarBleApiCallback.html":[1,0,0,0,0,0,3], "interfacepolar_1_1com_1_1sdk_1_1api_1_1PolarBleApiCallback.html#a2994bd2e8b3d80b4e4de9ad0bb0920e8":[1,0,0,0,0,0,3,0], -"interfacepolar_1_1com_1_1sdk_1_1api_1_1PolarBleApiCallback.html#a2cb360c2635633d6e78affa9a19b71b9":[1,0,0,0,0,0,3,8], "interfacepolar_1_1com_1_1sdk_1_1api_1_1PolarBleApiCallback.html#a2e4e8f71a75eebf87be49751fcf4b4e8":[1,0,0,0,0,0,3,3], "interfacepolar_1_1com_1_1sdk_1_1api_1_1PolarBleApiCallback.html#a3541b2cec92744126a84ec207f3e1211":[1,0,0,0,0,0,3,12], -"interfacepolar_1_1com_1_1sdk_1_1api_1_1PolarBleApiCallback.html#a3c2c3ff7eb76a8cba67057b60122b035":[1,0,0,0,0,0,3,4], -"interfacepolar_1_1com_1_1sdk_1_1api_1_1PolarBleApiCallback.html#a3ff1646ff47dcd2a3cc5df276c0d1f6d":[1,0,0,0,0,0,3,10], -"interfacepolar_1_1com_1_1sdk_1_1api_1_1PolarBleApiCallback.html#a4cceddbd2d8d2933893509f35d4cb4f9":[1,0,0,0,0,0,3,9], -"interfacepolar_1_1com_1_1sdk_1_1api_1_1PolarBleApiCallback.html#a535f9cd51fed5b5cb942043491805fce":[1,0,0,0,0,0,3,5], -"interfacepolar_1_1com_1_1sdk_1_1api_1_1PolarBleApiCallback.html#a60b5030d4ee50f7cf9d50bcbe2229808":[1,0,0,0,0,0,3,6], -"interfacepolar_1_1com_1_1sdk_1_1api_1_1PolarBleApiCallback.html#aa9534a4ec9f2269d19a112f54d2ec0e0":[1,0,0,0,0,0,3,7], +"interfacepolar_1_1com_1_1sdk_1_1api_1_1PolarBleApiCallback.html#a3c2c3ff7eb76a8cba67057b60122b035":[1,0,0,0,0,0,3,8], +"interfacepolar_1_1com_1_1sdk_1_1api_1_1PolarBleApiCallback.html#a60b5030d4ee50f7cf9d50bcbe2229808":[1,0,0,0,0,0,3,9], +"interfacepolar_1_1com_1_1sdk_1_1api_1_1PolarBleApiCallback.html#a8d2b40c2a8b2b14d98778f7542e337b8":[1,0,0,0,0,0,3,6], +"interfacepolar_1_1com_1_1sdk_1_1api_1_1PolarBleApiCallback.html#aa9534a4ec9f2269d19a112f54d2ec0e0":[1,0,0,0,0,0,3,10], +"interfacepolar_1_1com_1_1sdk_1_1api_1_1PolarBleApiCallback.html#ab6b0fa75da852019c7b74820e00f2cb9":[1,0,0,0,0,0,3,5], "interfacepolar_1_1com_1_1sdk_1_1api_1_1PolarBleApiCallback.html#ad2055f89f0e3a0d1dfce7a444b507698":[1,0,0,0,0,0,3,11], "interfacepolar_1_1com_1_1sdk_1_1api_1_1PolarBleApiCallback.html#ad98839ae9719804e7f93db93c03a3502":[1,0,0,0,0,0,3,1], +"interfacepolar_1_1com_1_1sdk_1_1api_1_1PolarBleApiCallback.html#ae9028fa8d2b8a017db6c01d061a69c8e":[1,0,0,0,0,0,3,7], +"interfacepolar_1_1com_1_1sdk_1_1api_1_1PolarBleApiCallback.html#ae98b2e7a18f12255b955693e1afc7bf2":[1,0,0,0,0,0,3,4], "interfacepolar_1_1com_1_1sdk_1_1api_1_1PolarBleApiCallback.html#af5ab3ec3f17b4f32085e9e085b0f38c3":[1,0,0,0,0,0,3,13], "interfacepolar_1_1com_1_1sdk_1_1api_1_1PolarBleApiCallback.html#afec6d56715ba82b46129812be452f1ba":[1,0,0,0,0,0,3,2], "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":[1,0,0], "namespacepolar.html":[0,0,0], -"namespacepolar_1_1com.html":[0,0,0,0], +"namespacepolar.html":[1,0,0], "namespacepolar_1_1com.html":[1,0,0,0], -"namespacepolar_1_1com_1_1sdk.html":[0,0,0,0,0], +"namespacepolar_1_1com.html":[0,0,0,0], "namespacepolar_1_1com_1_1sdk.html":[1,0,0,0,0], -"namespacepolar_1_1com_1_1sdk_1_1api.html":[0,0,0,0,0,0], +"namespacepolar_1_1com_1_1sdk.html":[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":[1,0,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_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":[0,0,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":[1,0,0,0,0,1], diff --git a/polar-sdk-ios/docs/API Default Implementation.html b/polar-sdk-ios/docs/API Default Implementation.html index e57191e5..a6dab838 100644 --- a/polar-sdk-ios/docs/API Default Implementation.html +++ b/polar-sdk-ios/docs/API Default Implementation.html @@ -195,8 +195,8 @@

Declaration

diff --git a/polar-sdk-ios/docs/API.html b/polar-sdk-ios/docs/API.html index f3f0f2b9..b3914291 100644 --- a/polar-sdk-ios/docs/API.html +++ b/polar-sdk-ios/docs/API.html @@ -399,8 +399,8 @@

Declaration

diff --git a/polar-sdk-ios/docs/Classes/PolarBleApiDefaultImpl.html b/polar-sdk-ios/docs/Classes/PolarBleApiDefaultImpl.html index c3f480d1..37376ee4 100644 --- a/polar-sdk-ios/docs/Classes/PolarBleApiDefaultImpl.html +++ b/polar-sdk-ios/docs/Classes/PolarBleApiDefaultImpl.html @@ -267,8 +267,8 @@

Return Value

diff --git a/polar-sdk-ios/docs/Enums/Features.html b/polar-sdk-ios/docs/Enums/Features.html index f410dcac..f6ccc6a2 100644 --- a/polar-sdk-ios/docs/Enums/Features.html +++ b/polar-sdk-ios/docs/Enums/Features.html @@ -337,8 +337,8 @@

Declaration

diff --git a/polar-sdk-ios/docs/Enums/SampleType.html b/polar-sdk-ios/docs/Enums/SampleType.html index d36ee657..5eb2426e 100644 --- a/polar-sdk-ios/docs/Enums/SampleType.html +++ b/polar-sdk-ios/docs/Enums/SampleType.html @@ -228,8 +228,8 @@

Declaration

diff --git a/polar-sdk-ios/docs/Other Enums.html b/polar-sdk-ios/docs/Other Enums.html index 93b2a74a..f6f24ad9 100644 --- a/polar-sdk-ios/docs/Other Enums.html +++ b/polar-sdk-ios/docs/Other Enums.html @@ -251,8 +251,8 @@

Declaration

diff --git a/polar-sdk-ios/docs/Other Typealiases.html b/polar-sdk-ios/docs/Other Typealiases.html index bf57ac55..8eb2e293 100644 --- a/polar-sdk-ios/docs/Other Typealiases.html +++ b/polar-sdk-ios/docs/Other Typealiases.html @@ -177,7 +177,7 @@

Other Type Aliases

Polar device info

-
- deviceId = Device id extracted from local device name
+
- deviceId = polar device id or UUID for 3rd party sensors
 - rssi = RSSI (Received Signal Strenght Indicator) value from advertisement
 - name = local name from advertisement
 - connectable = true adv type is connectable
@@ -188,7 +188,7 @@ 

Other Type Aliases

Declaration

Swift

-
public typealias PolarDeviceInfo = (deviceId: String, rssi: Int, name: String, connectable: Bool)
+
public typealias PolarDeviceInfo = (deviceId: String, address: UUID, rssi: Int, name: String, connectable: Bool)
@@ -445,8 +445,8 @@

Declaration

diff --git a/polar-sdk-ios/docs/PolarErrors.html b/polar-sdk-ios/docs/PolarErrors.html index c49f73ea..47986a22 100644 --- a/polar-sdk-ios/docs/PolarErrors.html +++ b/polar-sdk-ios/docs/PolarErrors.html @@ -464,8 +464,8 @@

Declaration

diff --git a/polar-sdk-ios/docs/Protocols/PolarBleApi.html b/polar-sdk-ios/docs/Protocols/PolarBleApi.html index 9304c62e..9d2109c2 100644 --- a/polar-sdk-ios/docs/Protocols/PolarBleApi.html +++ b/polar-sdk-ios/docs/Protocols/PolarBleApi.html @@ -199,9 +199,9 @@

Declaration

  • @@ -209,7 +209,53 @@

    Declaration

    -

    Start connecting to a nearby Polar device. PolarBleApiObservers polarDeviceConnected is +

    Enable or disable polar filter.

    + +
    +
    +

    Declaration

    +
    +

    Swift

    +
    func polarFilter(_ enable: Bool)
    + +
    +
    +
    +

    Parameters

    + + + + + + + +
    + + enable + + +
    +

    false disable polar filter

    +
    +
    +
    +
    +
    +
  • +
  • + +
    +
    +
    +
    +
    +

    Start connecting to a nearby device. PolarBleApiObservers polarDeviceConnected is invoked when a connection is established.

    @@ -217,7 +263,7 @@

    Declaration

    Declaration

    Swift

    -
    func startAutoConnectToPolarDevice(_ rssi: Int, polarDeviceType: String?) -> Completable
    +
    func startAutoConnectToDevice(_ rssi: Int, service: CBUUID?, polarDeviceType: String?) -> Completable
    @@ -262,9 +308,9 @@

    Return Value

  • @@ -279,7 +325,7 @@

    Return Value

    Declaration

    Swift

    -
    func connectToPolarDevice(_ identifier: String)
    +
    func connectToDevice(_ identifier: String)
    @@ -295,7 +341,7 @@

    Parameters

    -

    Polar device id printed on the sensor/device.

    +

    Polar device id printed on the sensor/device or UUID.

    @@ -308,9 +354,9 @@

    Parameters

  • @@ -325,7 +371,7 @@

    Parameters

    Declaration

    Swift

    -
    func disconnectFromPolarDevice(_ identifier: String)
    +
    func disconnectFromDevice(_ identifier: String)
    @@ -354,9 +400,9 @@

    Parameters

  • @@ -371,7 +417,7 @@

    Parameters

    Declaration

    Swift

    -
    func searchForPolarDevice() -> Observable<PolarDeviceInfo>
    +
    func searchForDevice() -> Observable<PolarDeviceInfo>
    @@ -441,7 +487,7 @@

    Parameters

    -

    polar device id

    +

    polar device id or UUID

    @@ -503,7 +549,7 @@

    Parameters

    -

    polar device id

    +

    polar device id or UUID

    @@ -582,7 +628,7 @@

    Parameters

    -

    Polar device id

    +

    Polar device id or UUID

    @@ -673,7 +719,7 @@

    Parameters

    -

    Polar device id

    +

    Polar device id or UUID

    @@ -750,9 +796,9 @@

    Return Value

  • @@ -1605,8 +1651,8 @@

    Declaration

    diff --git a/polar-sdk-ios/docs/Protocols/PolarBleApiDeviceFeaturesObserver.html b/polar-sdk-ios/docs/Protocols/PolarBleApiDeviceFeaturesObserver.html index 5d468a6f..b5ee111a 100644 --- a/polar-sdk-ios/docs/Protocols/PolarBleApiDeviceFeaturesObserver.html +++ b/polar-sdk-ios/docs/Protocols/PolarBleApiDeviceFeaturesObserver.html @@ -451,8 +451,8 @@

    Parameters

    diff --git a/polar-sdk-ios/docs/Protocols/PolarBleApiDeviceHrObserver.html b/polar-sdk-ios/docs/Protocols/PolarBleApiDeviceHrObserver.html index 668fc7b5..a2e93dd6 100644 --- a/polar-sdk-ios/docs/Protocols/PolarBleApiDeviceHrObserver.html +++ b/polar-sdk-ios/docs/Protocols/PolarBleApiDeviceHrObserver.html @@ -253,8 +253,8 @@

    Parameters

    diff --git a/polar-sdk-ios/docs/Protocols/PolarBleApiDeviceInfoObserver.html b/polar-sdk-ios/docs/Protocols/PolarBleApiDeviceInfoObserver.html index 94d4cbd2..69c4dbbf 100644 --- a/polar-sdk-ios/docs/Protocols/PolarBleApiDeviceInfoObserver.html +++ b/polar-sdk-ios/docs/Protocols/PolarBleApiDeviceInfoObserver.html @@ -230,9 +230,9 @@

    Parameters

  • @@ -240,14 +240,14 @@

    Parameters

    -

    Received firmware version info.

    +

    Received DIS info.

    Declaration

    Swift

    -
    func fwVersionReceived(_ identifier: String, fwVersion: String)
    +
    func disInformationReceived(_ identifier: String, uuid: CBUUID, value: String)
    @@ -259,8 +259,8 @@

    Declaration

    diff --git a/polar-sdk-ios/docs/Protocols/PolarBleApiLogger.html b/polar-sdk-ios/docs/Protocols/PolarBleApiLogger.html index 5630877e..373b09c5 100644 --- a/polar-sdk-ios/docs/Protocols/PolarBleApiLogger.html +++ b/polar-sdk-ios/docs/Protocols/PolarBleApiLogger.html @@ -220,8 +220,8 @@

    Parameters

    diff --git a/polar-sdk-ios/docs/Protocols/PolarBleApiObserver.html b/polar-sdk-ios/docs/Protocols/PolarBleApiObserver.html index 7ef25d7c..027f26dc 100644 --- a/polar-sdk-ios/docs/Protocols/PolarBleApiObserver.html +++ b/polar-sdk-ios/docs/Protocols/PolarBleApiObserver.html @@ -172,9 +172,9 @@

    PolarBleApiObserver

  • @@ -182,14 +182,14 @@

    PolarBleApiObserver

    -

    Callback when connection attempt is started to polar device

    +

    Callback when connection attempt is started to device

    Declaration

    Swift

    -
    func polarDeviceConnecting(_ identifier: PolarDeviceInfo)
    +
    func deviceConnecting(_ identifier: PolarDeviceInfo)
    @@ -205,7 +205,7 @@

    Parameters

    -

    Polar device inof

    +

    Polar device info

    @@ -218,9 +218,9 @@

    Parameters

  • @@ -235,7 +235,7 @@

    Parameters

    Declaration

    Swift

    -
    func polarDeviceConnected(_ identifier: PolarDeviceInfo)
    +
    func deviceConnected(_ identifier: PolarDeviceInfo)
    @@ -264,9 +264,9 @@

    Parameters

  • @@ -274,7 +274,7 @@

    Parameters

    -

    Connection lost to Polar device. +

    Connection lost to device. If PolarBleApi#disconnectFromPolarDevice is not called, a new connection attempt is dispatched automatically.

    @@ -282,7 +282,7 @@

    Parameters

    Declaration

    Swift

    -
    func polarDeviceDisconnected(_ identifier: PolarDeviceInfo)
    +
    func deviceDisconnected(_ identifier: PolarDeviceInfo)
    @@ -313,8 +313,8 @@

    Parameters

  • diff --git a/polar-sdk-ios/docs/Protocols/PolarBleApiPowerStateObserver.html b/polar-sdk-ios/docs/Protocols/PolarBleApiPowerStateObserver.html index b8745d51..b57f278c 100644 --- a/polar-sdk-ios/docs/Protocols/PolarBleApiPowerStateObserver.html +++ b/polar-sdk-ios/docs/Protocols/PolarBleApiPowerStateObserver.html @@ -228,8 +228,8 @@

    Declaration

    diff --git a/polar-sdk-ios/docs/Structs/PolarSensorSetting.html b/polar-sdk-ios/docs/Structs/PolarSensorSetting.html index a5961c30..6fe8bfda 100644 --- a/polar-sdk-ios/docs/Structs/PolarSensorSetting.html +++ b/polar-sdk-ios/docs/Structs/PolarSensorSetting.html @@ -306,8 +306,8 @@

    Return Value

    diff --git a/polar-sdk-ios/docs/Structs/PolarSensorSetting/SettingType.html b/polar-sdk-ios/docs/Structs/PolarSensorSetting/SettingType.html index e9bef777..23bd10e9 100644 --- a/polar-sdk-ios/docs/Structs/PolarSensorSetting/SettingType.html +++ b/polar-sdk-ios/docs/Structs/PolarSensorSetting/SettingType.html @@ -282,8 +282,8 @@

    Declaration

    diff --git a/polar-sdk-ios/docs/docsets/.docset/Contents/Resources/Documents/API Default Implementation.html b/polar-sdk-ios/docs/docsets/.docset/Contents/Resources/Documents/API Default Implementation.html index e57191e5..a6dab838 100644 --- a/polar-sdk-ios/docs/docsets/.docset/Contents/Resources/Documents/API Default Implementation.html +++ b/polar-sdk-ios/docs/docsets/.docset/Contents/Resources/Documents/API Default Implementation.html @@ -195,8 +195,8 @@

    Declaration

    diff --git a/polar-sdk-ios/docs/docsets/.docset/Contents/Resources/Documents/API.html b/polar-sdk-ios/docs/docsets/.docset/Contents/Resources/Documents/API.html index f3f0f2b9..b3914291 100644 --- a/polar-sdk-ios/docs/docsets/.docset/Contents/Resources/Documents/API.html +++ b/polar-sdk-ios/docs/docsets/.docset/Contents/Resources/Documents/API.html @@ -399,8 +399,8 @@

    Declaration

    diff --git a/polar-sdk-ios/docs/docsets/.docset/Contents/Resources/Documents/Classes/PolarBleApiDefaultImpl.html b/polar-sdk-ios/docs/docsets/.docset/Contents/Resources/Documents/Classes/PolarBleApiDefaultImpl.html index c3f480d1..37376ee4 100644 --- a/polar-sdk-ios/docs/docsets/.docset/Contents/Resources/Documents/Classes/PolarBleApiDefaultImpl.html +++ b/polar-sdk-ios/docs/docsets/.docset/Contents/Resources/Documents/Classes/PolarBleApiDefaultImpl.html @@ -267,8 +267,8 @@

    Return Value

    diff --git a/polar-sdk-ios/docs/docsets/.docset/Contents/Resources/Documents/Enums/Features.html b/polar-sdk-ios/docs/docsets/.docset/Contents/Resources/Documents/Enums/Features.html index f410dcac..f6ccc6a2 100644 --- a/polar-sdk-ios/docs/docsets/.docset/Contents/Resources/Documents/Enums/Features.html +++ b/polar-sdk-ios/docs/docsets/.docset/Contents/Resources/Documents/Enums/Features.html @@ -337,8 +337,8 @@

    Declaration

    diff --git a/polar-sdk-ios/docs/docsets/.docset/Contents/Resources/Documents/Enums/SampleType.html b/polar-sdk-ios/docs/docsets/.docset/Contents/Resources/Documents/Enums/SampleType.html index d36ee657..5eb2426e 100644 --- a/polar-sdk-ios/docs/docsets/.docset/Contents/Resources/Documents/Enums/SampleType.html +++ b/polar-sdk-ios/docs/docsets/.docset/Contents/Resources/Documents/Enums/SampleType.html @@ -228,8 +228,8 @@

    Declaration

    diff --git a/polar-sdk-ios/docs/docsets/.docset/Contents/Resources/Documents/Other Enums.html b/polar-sdk-ios/docs/docsets/.docset/Contents/Resources/Documents/Other Enums.html index 93b2a74a..f6f24ad9 100644 --- a/polar-sdk-ios/docs/docsets/.docset/Contents/Resources/Documents/Other Enums.html +++ b/polar-sdk-ios/docs/docsets/.docset/Contents/Resources/Documents/Other Enums.html @@ -251,8 +251,8 @@

    Declaration

    diff --git a/polar-sdk-ios/docs/docsets/.docset/Contents/Resources/Documents/Other Typealiases.html b/polar-sdk-ios/docs/docsets/.docset/Contents/Resources/Documents/Other Typealiases.html index bf57ac55..8eb2e293 100644 --- a/polar-sdk-ios/docs/docsets/.docset/Contents/Resources/Documents/Other Typealiases.html +++ b/polar-sdk-ios/docs/docsets/.docset/Contents/Resources/Documents/Other Typealiases.html @@ -177,7 +177,7 @@

    Other Type Aliases

    Polar device info

    -
    - deviceId = Device id extracted from local device name
    +
    - deviceId = polar device id or UUID for 3rd party sensors
     - rssi = RSSI (Received Signal Strenght Indicator) value from advertisement
     - name = local name from advertisement
     - connectable = true adv type is connectable
    @@ -188,7 +188,7 @@ 

    Other Type Aliases

    Declaration

    Swift

    -
    public typealias PolarDeviceInfo = (deviceId: String, rssi: Int, name: String, connectable: Bool)
    +
    public typealias PolarDeviceInfo = (deviceId: String, address: UUID, rssi: Int, name: String, connectable: Bool)
    @@ -445,8 +445,8 @@

    Declaration

    diff --git a/polar-sdk-ios/docs/docsets/.docset/Contents/Resources/Documents/PolarErrors.html b/polar-sdk-ios/docs/docsets/.docset/Contents/Resources/Documents/PolarErrors.html index c49f73ea..47986a22 100644 --- a/polar-sdk-ios/docs/docsets/.docset/Contents/Resources/Documents/PolarErrors.html +++ b/polar-sdk-ios/docs/docsets/.docset/Contents/Resources/Documents/PolarErrors.html @@ -464,8 +464,8 @@

    Declaration

    diff --git a/polar-sdk-ios/docs/docsets/.docset/Contents/Resources/Documents/Protocols/PolarBleApi.html b/polar-sdk-ios/docs/docsets/.docset/Contents/Resources/Documents/Protocols/PolarBleApi.html index 9304c62e..9d2109c2 100644 --- a/polar-sdk-ios/docs/docsets/.docset/Contents/Resources/Documents/Protocols/PolarBleApi.html +++ b/polar-sdk-ios/docs/docsets/.docset/Contents/Resources/Documents/Protocols/PolarBleApi.html @@ -199,9 +199,9 @@

    Declaration

  • @@ -209,7 +209,53 @@

    Declaration

    -

    Start connecting to a nearby Polar device. PolarBleApiObservers polarDeviceConnected is +

    Enable or disable polar filter.

    + +
    +
    +

    Declaration

    +
    +

    Swift

    +
    func polarFilter(_ enable: Bool)
    + +
    +
    +
    +

    Parameters

    + + + + + + + +
    + + enable + + +
    +

    false disable polar filter

    +
    +
    +
    +
    +
    +
  • +
  • + +
    +
    +
    +
    +
    +

    Start connecting to a nearby device. PolarBleApiObservers polarDeviceConnected is invoked when a connection is established.

    @@ -217,7 +263,7 @@

    Declaration

    Declaration

    Swift

    -
    func startAutoConnectToPolarDevice(_ rssi: Int, polarDeviceType: String?) -> Completable
    +
    func startAutoConnectToDevice(_ rssi: Int, service: CBUUID?, polarDeviceType: String?) -> Completable
    @@ -262,9 +308,9 @@

    Return Value

  • @@ -279,7 +325,7 @@

    Return Value

    Declaration

    Swift

    -
    func connectToPolarDevice(_ identifier: String)
    +
    func connectToDevice(_ identifier: String)
    @@ -295,7 +341,7 @@

    Parameters

    -

    Polar device id printed on the sensor/device.

    +

    Polar device id printed on the sensor/device or UUID.

    @@ -308,9 +354,9 @@

    Parameters

  • @@ -325,7 +371,7 @@

    Parameters

    Declaration

    Swift

    -
    func disconnectFromPolarDevice(_ identifier: String)
    +
    func disconnectFromDevice(_ identifier: String)
    @@ -354,9 +400,9 @@

    Parameters

  • @@ -371,7 +417,7 @@

    Parameters

    Declaration

    Swift

    -
    func searchForPolarDevice() -> Observable<PolarDeviceInfo>
    +
    func searchForDevice() -> Observable<PolarDeviceInfo>
    @@ -441,7 +487,7 @@

    Parameters

    -

    polar device id

    +

    polar device id or UUID

    @@ -503,7 +549,7 @@

    Parameters

    -

    polar device id

    +

    polar device id or UUID

    @@ -582,7 +628,7 @@

    Parameters

    -

    Polar device id

    +

    Polar device id or UUID

    @@ -673,7 +719,7 @@

    Parameters

    -

    Polar device id

    +

    Polar device id or UUID

    @@ -750,9 +796,9 @@

    Return Value

  • @@ -1605,8 +1651,8 @@

    Declaration

    diff --git a/polar-sdk-ios/docs/docsets/.docset/Contents/Resources/Documents/Protocols/PolarBleApiDeviceFeaturesObserver.html b/polar-sdk-ios/docs/docsets/.docset/Contents/Resources/Documents/Protocols/PolarBleApiDeviceFeaturesObserver.html index 5d468a6f..b5ee111a 100644 --- a/polar-sdk-ios/docs/docsets/.docset/Contents/Resources/Documents/Protocols/PolarBleApiDeviceFeaturesObserver.html +++ b/polar-sdk-ios/docs/docsets/.docset/Contents/Resources/Documents/Protocols/PolarBleApiDeviceFeaturesObserver.html @@ -451,8 +451,8 @@

    Parameters

    diff --git a/polar-sdk-ios/docs/docsets/.docset/Contents/Resources/Documents/Protocols/PolarBleApiDeviceHrObserver.html b/polar-sdk-ios/docs/docsets/.docset/Contents/Resources/Documents/Protocols/PolarBleApiDeviceHrObserver.html index 668fc7b5..a2e93dd6 100644 --- a/polar-sdk-ios/docs/docsets/.docset/Contents/Resources/Documents/Protocols/PolarBleApiDeviceHrObserver.html +++ b/polar-sdk-ios/docs/docsets/.docset/Contents/Resources/Documents/Protocols/PolarBleApiDeviceHrObserver.html @@ -253,8 +253,8 @@

    Parameters

    diff --git a/polar-sdk-ios/docs/docsets/.docset/Contents/Resources/Documents/Protocols/PolarBleApiDeviceInfoObserver.html b/polar-sdk-ios/docs/docsets/.docset/Contents/Resources/Documents/Protocols/PolarBleApiDeviceInfoObserver.html index 94d4cbd2..69c4dbbf 100644 --- a/polar-sdk-ios/docs/docsets/.docset/Contents/Resources/Documents/Protocols/PolarBleApiDeviceInfoObserver.html +++ b/polar-sdk-ios/docs/docsets/.docset/Contents/Resources/Documents/Protocols/PolarBleApiDeviceInfoObserver.html @@ -230,9 +230,9 @@

    Parameters

  • @@ -240,14 +240,14 @@

    Parameters

    -

    Received firmware version info.

    +

    Received DIS info.

    Declaration

    Swift

    -
    func fwVersionReceived(_ identifier: String, fwVersion: String)
    +
    func disInformationReceived(_ identifier: String, uuid: CBUUID, value: String)
    @@ -259,8 +259,8 @@

    Declaration

    diff --git a/polar-sdk-ios/docs/docsets/.docset/Contents/Resources/Documents/Protocols/PolarBleApiLogger.html b/polar-sdk-ios/docs/docsets/.docset/Contents/Resources/Documents/Protocols/PolarBleApiLogger.html index 5630877e..373b09c5 100644 --- a/polar-sdk-ios/docs/docsets/.docset/Contents/Resources/Documents/Protocols/PolarBleApiLogger.html +++ b/polar-sdk-ios/docs/docsets/.docset/Contents/Resources/Documents/Protocols/PolarBleApiLogger.html @@ -220,8 +220,8 @@

    Parameters

    diff --git a/polar-sdk-ios/docs/docsets/.docset/Contents/Resources/Documents/Protocols/PolarBleApiObserver.html b/polar-sdk-ios/docs/docsets/.docset/Contents/Resources/Documents/Protocols/PolarBleApiObserver.html index 7ef25d7c..027f26dc 100644 --- a/polar-sdk-ios/docs/docsets/.docset/Contents/Resources/Documents/Protocols/PolarBleApiObserver.html +++ b/polar-sdk-ios/docs/docsets/.docset/Contents/Resources/Documents/Protocols/PolarBleApiObserver.html @@ -172,9 +172,9 @@

    PolarBleApiObserver

  • @@ -182,14 +182,14 @@

    PolarBleApiObserver

    -

    Callback when connection attempt is started to polar device

    +

    Callback when connection attempt is started to device

    Declaration

    Swift

    -
    func polarDeviceConnecting(_ identifier: PolarDeviceInfo)
    +
    func deviceConnecting(_ identifier: PolarDeviceInfo)
    @@ -205,7 +205,7 @@

    Parameters

    -

    Polar device inof

    +

    Polar device info

    @@ -218,9 +218,9 @@

    Parameters

  • @@ -235,7 +235,7 @@

    Parameters

    Declaration

    Swift

    -
    func polarDeviceConnected(_ identifier: PolarDeviceInfo)
    +
    func deviceConnected(_ identifier: PolarDeviceInfo)
    @@ -264,9 +264,9 @@

    Parameters

  • @@ -274,7 +274,7 @@

    Parameters

    -

    Connection lost to Polar device. +

    Connection lost to device. If PolarBleApi#disconnectFromPolarDevice is not called, a new connection attempt is dispatched automatically.

    @@ -282,7 +282,7 @@

    Parameters

    Declaration

    Swift

    -
    func polarDeviceDisconnected(_ identifier: PolarDeviceInfo)
    +
    func deviceDisconnected(_ identifier: PolarDeviceInfo)
    @@ -313,8 +313,8 @@

    Parameters

  • diff --git a/polar-sdk-ios/docs/docsets/.docset/Contents/Resources/Documents/Protocols/PolarBleApiPowerStateObserver.html b/polar-sdk-ios/docs/docsets/.docset/Contents/Resources/Documents/Protocols/PolarBleApiPowerStateObserver.html index b8745d51..b57f278c 100644 --- a/polar-sdk-ios/docs/docsets/.docset/Contents/Resources/Documents/Protocols/PolarBleApiPowerStateObserver.html +++ b/polar-sdk-ios/docs/docsets/.docset/Contents/Resources/Documents/Protocols/PolarBleApiPowerStateObserver.html @@ -228,8 +228,8 @@

    Declaration

    diff --git a/polar-sdk-ios/docs/docsets/.docset/Contents/Resources/Documents/Structs/PolarSensorSetting.html b/polar-sdk-ios/docs/docsets/.docset/Contents/Resources/Documents/Structs/PolarSensorSetting.html index a5961c30..6fe8bfda 100644 --- a/polar-sdk-ios/docs/docsets/.docset/Contents/Resources/Documents/Structs/PolarSensorSetting.html +++ b/polar-sdk-ios/docs/docsets/.docset/Contents/Resources/Documents/Structs/PolarSensorSetting.html @@ -306,8 +306,8 @@

    Return Value

    diff --git a/polar-sdk-ios/docs/docsets/.docset/Contents/Resources/Documents/Structs/PolarSensorSetting/SettingType.html b/polar-sdk-ios/docs/docsets/.docset/Contents/Resources/Documents/Structs/PolarSensorSetting/SettingType.html index e9bef777..23bd10e9 100644 --- a/polar-sdk-ios/docs/docsets/.docset/Contents/Resources/Documents/Structs/PolarSensorSetting/SettingType.html +++ b/polar-sdk-ios/docs/docsets/.docset/Contents/Resources/Documents/Structs/PolarSensorSetting/SettingType.html @@ -282,8 +282,8 @@

    Declaration

    diff --git a/polar-sdk-ios/docs/docsets/.docset/Contents/Resources/Documents/index.html b/polar-sdk-ios/docs/docsets/.docset/Contents/Resources/Documents/index.html index abb50e74..64868751 100644 --- a/polar-sdk-ios/docs/docsets/.docset/Contents/Resources/Documents/index.html +++ b/polar-sdk-ios/docs/docsets/.docset/Contents/Resources/Documents/index.html @@ -161,8 +161,8 @@ diff --git a/polar-sdk-ios/docs/docsets/.docset/Contents/Resources/Documents/js/jazzy.js b/polar-sdk-ios/docs/docsets/.docset/Contents/Resources/Documents/js/jazzy.js index 3965b5fb..4ff9455b 100755 --- a/polar-sdk-ios/docs/docsets/.docset/Contents/Resources/Documents/js/jazzy.js +++ b/polar-sdk-ios/docs/docsets/.docset/Contents/Resources/Documents/js/jazzy.js @@ -38,9 +38,3 @@ $(".token").click(function(event) { } event.preventDefault(); }); - -// Dumb down quotes within code blocks that delimit strings instead of quotations -// https://github.com/realm/jazzy/issues/714 -$("code q").replaceWith(function () { - return ["\"", $(this).contents(), "\""]; -}); diff --git a/polar-sdk-ios/docs/docsets/.docset/Contents/Resources/Documents/js/jquery.min.js b/polar-sdk-ios/docs/docsets/.docset/Contents/Resources/Documents/js/jquery.min.js old mode 100755 new mode 100644 index ab28a247..4d9b3a25 --- a/polar-sdk-ios/docs/docsets/.docset/Contents/Resources/Documents/js/jquery.min.js +++ b/polar-sdk-ios/docs/docsets/.docset/Contents/Resources/Documents/js/jquery.min.js @@ -1,4 +1,2 @@ -/*! jQuery v1.11.1 | (c) 2005, 2014 jQuery Foundation, Inc. | jquery.org/license */ -!function(a,b){"object"==typeof module&&"object"==typeof module.exports?module.exports=a.document?b(a,!0):function(a){if(!a.document)throw new Error("jQuery requires a window with a document");return b(a)}:b(a)}("undefined"!=typeof window?window:this,function(a,b){var c=[],d=c.slice,e=c.concat,f=c.push,g=c.indexOf,h={},i=h.toString,j=h.hasOwnProperty,k={},l="1.11.1",m=function(a,b){return new m.fn.init(a,b)},n=/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g,o=/^-ms-/,p=/-([\da-z])/gi,q=function(a,b){return b.toUpperCase()};m.fn=m.prototype={jquery:l,constructor:m,selector:"",length:0,toArray:function(){return d.call(this)},get:function(a){return null!=a?0>a?this[a+this.length]:this[a]:d.call(this)},pushStack:function(a){var b=m.merge(this.constructor(),a);return b.prevObject=this,b.context=this.context,b},each:function(a,b){return m.each(this,a,b)},map:function(a){return this.pushStack(m.map(this,function(b,c){return a.call(b,c,b)}))},slice:function(){return this.pushStack(d.apply(this,arguments))},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},eq:function(a){var b=this.length,c=+a+(0>a?b:0);return this.pushStack(c>=0&&b>c?[this[c]]:[])},end:function(){return this.prevObject||this.constructor(null)},push:f,sort:c.sort,splice:c.splice},m.extend=m.fn.extend=function(){var a,b,c,d,e,f,g=arguments[0]||{},h=1,i=arguments.length,j=!1;for("boolean"==typeof g&&(j=g,g=arguments[h]||{},h++),"object"==typeof g||m.isFunction(g)||(g={}),h===i&&(g=this,h--);i>h;h++)if(null!=(e=arguments[h]))for(d in e)a=g[d],c=e[d],g!==c&&(j&&c&&(m.isPlainObject(c)||(b=m.isArray(c)))?(b?(b=!1,f=a&&m.isArray(a)?a:[]):f=a&&m.isPlainObject(a)?a:{},g[d]=m.extend(j,f,c)):void 0!==c&&(g[d]=c));return g},m.extend({expando:"jQuery"+(l+Math.random()).replace(/\D/g,""),isReady:!0,error:function(a){throw new Error(a)},noop:function(){},isFunction:function(a){return"function"===m.type(a)},isArray:Array.isArray||function(a){return"array"===m.type(a)},isWindow:function(a){return null!=a&&a==a.window},isNumeric:function(a){return!m.isArray(a)&&a-parseFloat(a)>=0},isEmptyObject:function(a){var b;for(b in a)return!1;return!0},isPlainObject:function(a){var b;if(!a||"object"!==m.type(a)||a.nodeType||m.isWindow(a))return!1;try{if(a.constructor&&!j.call(a,"constructor")&&!j.call(a.constructor.prototype,"isPrototypeOf"))return!1}catch(c){return!1}if(k.ownLast)for(b in a)return j.call(a,b);for(b in a);return void 0===b||j.call(a,b)},type:function(a){return null==a?a+"":"object"==typeof a||"function"==typeof a?h[i.call(a)]||"object":typeof a},globalEval:function(b){b&&m.trim(b)&&(a.execScript||function(b){a.eval.call(a,b)})(b)},camelCase:function(a){return a.replace(o,"ms-").replace(p,q)},nodeName:function(a,b){return a.nodeName&&a.nodeName.toLowerCase()===b.toLowerCase()},each:function(a,b,c){var d,e=0,f=a.length,g=r(a);if(c){if(g){for(;f>e;e++)if(d=b.apply(a[e],c),d===!1)break}else for(e in a)if(d=b.apply(a[e],c),d===!1)break}else if(g){for(;f>e;e++)if(d=b.call(a[e],e,a[e]),d===!1)break}else for(e in a)if(d=b.call(a[e],e,a[e]),d===!1)break;return a},trim:function(a){return null==a?"":(a+"").replace(n,"")},makeArray:function(a,b){var c=b||[];return null!=a&&(r(Object(a))?m.merge(c,"string"==typeof a?[a]:a):f.call(c,a)),c},inArray:function(a,b,c){var d;if(b){if(g)return g.call(b,a,c);for(d=b.length,c=c?0>c?Math.max(0,d+c):c:0;d>c;c++)if(c in b&&b[c]===a)return c}return-1},merge:function(a,b){var c=+b.length,d=0,e=a.length;while(c>d)a[e++]=b[d++];if(c!==c)while(void 0!==b[d])a[e++]=b[d++];return a.length=e,a},grep:function(a,b,c){for(var d,e=[],f=0,g=a.length,h=!c;g>f;f++)d=!b(a[f],f),d!==h&&e.push(a[f]);return e},map:function(a,b,c){var d,f=0,g=a.length,h=r(a),i=[];if(h)for(;g>f;f++)d=b(a[f],f,c),null!=d&&i.push(d);else for(f in a)d=b(a[f],f,c),null!=d&&i.push(d);return e.apply([],i)},guid:1,proxy:function(a,b){var c,e,f;return"string"==typeof b&&(f=a[b],b=a,a=f),m.isFunction(a)?(c=d.call(arguments,2),e=function(){return a.apply(b||this,c.concat(d.call(arguments)))},e.guid=a.guid=a.guid||m.guid++,e):void 0},now:function(){return+new Date},support:k}),m.each("Boolean Number String Function Array Date RegExp Object Error".split(" "),function(a,b){h["[object "+b+"]"]=b.toLowerCase()});function r(a){var b=a.length,c=m.type(a);return"function"===c||m.isWindow(a)?!1:1===a.nodeType&&b?!0:"array"===c||0===b||"number"==typeof b&&b>0&&b-1 in a}var s=function(a){var b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u="sizzle"+-new Date,v=a.document,w=0,x=0,y=gb(),z=gb(),A=gb(),B=function(a,b){return a===b&&(l=!0),0},C="undefined",D=1<<31,E={}.hasOwnProperty,F=[],G=F.pop,H=F.push,I=F.push,J=F.slice,K=F.indexOf||function(a){for(var b=0,c=this.length;c>b;b++)if(this[b]===a)return b;return-1},L="checked|selected|async|autofocus|autoplay|controls|defer|disabled|hidden|ismap|loop|multiple|open|readonly|required|scoped",M="[\\x20\\t\\r\\n\\f]",N="(?:\\\\.|[\\w-]|[^\\x00-\\xa0])+",O=N.replace("w","w#"),P="\\["+M+"*("+N+")(?:"+M+"*([*^$|!~]?=)"+M+"*(?:'((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\"|("+O+"))|)"+M+"*\\]",Q=":("+N+")(?:\\((('((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\")|((?:\\\\.|[^\\\\()[\\]]|"+P+")*)|.*)\\)|)",R=new RegExp("^"+M+"+|((?:^|[^\\\\])(?:\\\\.)*)"+M+"+$","g"),S=new RegExp("^"+M+"*,"+M+"*"),T=new RegExp("^"+M+"*([>+~]|"+M+")"+M+"*"),U=new RegExp("="+M+"*([^\\]'\"]*?)"+M+"*\\]","g"),V=new RegExp(Q),W=new RegExp("^"+O+"$"),X={ID:new RegExp("^#("+N+")"),CLASS:new RegExp("^\\.("+N+")"),TAG:new RegExp("^("+N.replace("w","w*")+")"),ATTR:new RegExp("^"+P),PSEUDO:new RegExp("^"+Q),CHILD:new RegExp("^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\("+M+"*(even|odd|(([+-]|)(\\d*)n|)"+M+"*(?:([+-]|)"+M+"*(\\d+)|))"+M+"*\\)|)","i"),bool:new RegExp("^(?:"+L+")$","i"),needsContext:new RegExp("^"+M+"*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\("+M+"*((?:-\\d)?\\d*)"+M+"*\\)|)(?=[^-]|$)","i")},Y=/^(?:input|select|textarea|button)$/i,Z=/^h\d$/i,$=/^[^{]+\{\s*\[native \w/,_=/^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/,ab=/[+~]/,bb=/'|\\/g,cb=new RegExp("\\\\([\\da-f]{1,6}"+M+"?|("+M+")|.)","ig"),db=function(a,b,c){var d="0x"+b-65536;return d!==d||c?b:0>d?String.fromCharCode(d+65536):String.fromCharCode(d>>10|55296,1023&d|56320)};try{I.apply(F=J.call(v.childNodes),v.childNodes),F[v.childNodes.length].nodeType}catch(eb){I={apply:F.length?function(a,b){H.apply(a,J.call(b))}:function(a,b){var c=a.length,d=0;while(a[c++]=b[d++]);a.length=c-1}}}function fb(a,b,d,e){var f,h,j,k,l,o,r,s,w,x;if((b?b.ownerDocument||b:v)!==n&&m(b),b=b||n,d=d||[],!a||"string"!=typeof a)return d;if(1!==(k=b.nodeType)&&9!==k)return[];if(p&&!e){if(f=_.exec(a))if(j=f[1]){if(9===k){if(h=b.getElementById(j),!h||!h.parentNode)return d;if(h.id===j)return d.push(h),d}else if(b.ownerDocument&&(h=b.ownerDocument.getElementById(j))&&t(b,h)&&h.id===j)return d.push(h),d}else{if(f[2])return I.apply(d,b.getElementsByTagName(a)),d;if((j=f[3])&&c.getElementsByClassName&&b.getElementsByClassName)return I.apply(d,b.getElementsByClassName(j)),d}if(c.qsa&&(!q||!q.test(a))){if(s=r=u,w=b,x=9===k&&a,1===k&&"object"!==b.nodeName.toLowerCase()){o=g(a),(r=b.getAttribute("id"))?s=r.replace(bb,"\\$&"):b.setAttribute("id",s),s="[id='"+s+"'] ",l=o.length;while(l--)o[l]=s+qb(o[l]);w=ab.test(a)&&ob(b.parentNode)||b,x=o.join(",")}if(x)try{return I.apply(d,w.querySelectorAll(x)),d}catch(y){}finally{r||b.removeAttribute("id")}}}return i(a.replace(R,"$1"),b,d,e)}function gb(){var a=[];function b(c,e){return a.push(c+" ")>d.cacheLength&&delete b[a.shift()],b[c+" "]=e}return b}function hb(a){return a[u]=!0,a}function ib(a){var b=n.createElement("div");try{return!!a(b)}catch(c){return!1}finally{b.parentNode&&b.parentNode.removeChild(b),b=null}}function jb(a,b){var c=a.split("|"),e=a.length;while(e--)d.attrHandle[c[e]]=b}function kb(a,b){var c=b&&a,d=c&&1===a.nodeType&&1===b.nodeType&&(~b.sourceIndex||D)-(~a.sourceIndex||D);if(d)return d;if(c)while(c=c.nextSibling)if(c===b)return-1;return a?1:-1}function lb(a){return function(b){var c=b.nodeName.toLowerCase();return"input"===c&&b.type===a}}function mb(a){return function(b){var c=b.nodeName.toLowerCase();return("input"===c||"button"===c)&&b.type===a}}function nb(a){return hb(function(b){return b=+b,hb(function(c,d){var e,f=a([],c.length,b),g=f.length;while(g--)c[e=f[g]]&&(c[e]=!(d[e]=c[e]))})})}function ob(a){return a&&typeof a.getElementsByTagName!==C&&a}c=fb.support={},f=fb.isXML=function(a){var b=a&&(a.ownerDocument||a).documentElement;return b?"HTML"!==b.nodeName:!1},m=fb.setDocument=function(a){var b,e=a?a.ownerDocument||a:v,g=e.defaultView;return e!==n&&9===e.nodeType&&e.documentElement?(n=e,o=e.documentElement,p=!f(e),g&&g!==g.top&&(g.addEventListener?g.addEventListener("unload",function(){m()},!1):g.attachEvent&&g.attachEvent("onunload",function(){m()})),c.attributes=ib(function(a){return a.className="i",!a.getAttribute("className")}),c.getElementsByTagName=ib(function(a){return a.appendChild(e.createComment("")),!a.getElementsByTagName("*").length}),c.getElementsByClassName=$.test(e.getElementsByClassName)&&ib(function(a){return a.innerHTML="
    ",a.firstChild.className="i",2===a.getElementsByClassName("i").length}),c.getById=ib(function(a){return o.appendChild(a).id=u,!e.getElementsByName||!e.getElementsByName(u).length}),c.getById?(d.find.ID=function(a,b){if(typeof b.getElementById!==C&&p){var c=b.getElementById(a);return c&&c.parentNode?[c]:[]}},d.filter.ID=function(a){var b=a.replace(cb,db);return function(a){return a.getAttribute("id")===b}}):(delete d.find.ID,d.filter.ID=function(a){var b=a.replace(cb,db);return function(a){var c=typeof a.getAttributeNode!==C&&a.getAttributeNode("id");return c&&c.value===b}}),d.find.TAG=c.getElementsByTagName?function(a,b){return typeof b.getElementsByTagName!==C?b.getElementsByTagName(a):void 0}:function(a,b){var c,d=[],e=0,f=b.getElementsByTagName(a);if("*"===a){while(c=f[e++])1===c.nodeType&&d.push(c);return d}return f},d.find.CLASS=c.getElementsByClassName&&function(a,b){return typeof b.getElementsByClassName!==C&&p?b.getElementsByClassName(a):void 0},r=[],q=[],(c.qsa=$.test(e.querySelectorAll))&&(ib(function(a){a.innerHTML="",a.querySelectorAll("[msallowclip^='']").length&&q.push("[*^$]="+M+"*(?:''|\"\")"),a.querySelectorAll("[selected]").length||q.push("\\["+M+"*(?:value|"+L+")"),a.querySelectorAll(":checked").length||q.push(":checked")}),ib(function(a){var b=e.createElement("input");b.setAttribute("type","hidden"),a.appendChild(b).setAttribute("name","D"),a.querySelectorAll("[name=d]").length&&q.push("name"+M+"*[*^$|!~]?="),a.querySelectorAll(":enabled").length||q.push(":enabled",":disabled"),a.querySelectorAll("*,:x"),q.push(",.*:")})),(c.matchesSelector=$.test(s=o.matches||o.webkitMatchesSelector||o.mozMatchesSelector||o.oMatchesSelector||o.msMatchesSelector))&&ib(function(a){c.disconnectedMatch=s.call(a,"div"),s.call(a,"[s!='']:x"),r.push("!=",Q)}),q=q.length&&new RegExp(q.join("|")),r=r.length&&new RegExp(r.join("|")),b=$.test(o.compareDocumentPosition),t=b||$.test(o.contains)?function(a,b){var c=9===a.nodeType?a.documentElement:a,d=b&&b.parentNode;return a===d||!(!d||1!==d.nodeType||!(c.contains?c.contains(d):a.compareDocumentPosition&&16&a.compareDocumentPosition(d)))}:function(a,b){if(b)while(b=b.parentNode)if(b===a)return!0;return!1},B=b?function(a,b){if(a===b)return l=!0,0;var d=!a.compareDocumentPosition-!b.compareDocumentPosition;return d?d:(d=(a.ownerDocument||a)===(b.ownerDocument||b)?a.compareDocumentPosition(b):1,1&d||!c.sortDetached&&b.compareDocumentPosition(a)===d?a===e||a.ownerDocument===v&&t(v,a)?-1:b===e||b.ownerDocument===v&&t(v,b)?1:k?K.call(k,a)-K.call(k,b):0:4&d?-1:1)}:function(a,b){if(a===b)return l=!0,0;var c,d=0,f=a.parentNode,g=b.parentNode,h=[a],i=[b];if(!f||!g)return a===e?-1:b===e?1:f?-1:g?1:k?K.call(k,a)-K.call(k,b):0;if(f===g)return kb(a,b);c=a;while(c=c.parentNode)h.unshift(c);c=b;while(c=c.parentNode)i.unshift(c);while(h[d]===i[d])d++;return d?kb(h[d],i[d]):h[d]===v?-1:i[d]===v?1:0},e):n},fb.matches=function(a,b){return fb(a,null,null,b)},fb.matchesSelector=function(a,b){if((a.ownerDocument||a)!==n&&m(a),b=b.replace(U,"='$1']"),!(!c.matchesSelector||!p||r&&r.test(b)||q&&q.test(b)))try{var d=s.call(a,b);if(d||c.disconnectedMatch||a.document&&11!==a.document.nodeType)return d}catch(e){}return fb(b,n,null,[a]).length>0},fb.contains=function(a,b){return(a.ownerDocument||a)!==n&&m(a),t(a,b)},fb.attr=function(a,b){(a.ownerDocument||a)!==n&&m(a);var e=d.attrHandle[b.toLowerCase()],f=e&&E.call(d.attrHandle,b.toLowerCase())?e(a,b,!p):void 0;return void 0!==f?f:c.attributes||!p?a.getAttribute(b):(f=a.getAttributeNode(b))&&f.specified?f.value:null},fb.error=function(a){throw new Error("Syntax error, unrecognized expression: "+a)},fb.uniqueSort=function(a){var b,d=[],e=0,f=0;if(l=!c.detectDuplicates,k=!c.sortStable&&a.slice(0),a.sort(B),l){while(b=a[f++])b===a[f]&&(e=d.push(f));while(e--)a.splice(d[e],1)}return k=null,a},e=fb.getText=function(a){var b,c="",d=0,f=a.nodeType;if(f){if(1===f||9===f||11===f){if("string"==typeof a.textContent)return a.textContent;for(a=a.firstChild;a;a=a.nextSibling)c+=e(a)}else if(3===f||4===f)return a.nodeValue}else while(b=a[d++])c+=e(b);return c},d=fb.selectors={cacheLength:50,createPseudo:hb,match:X,attrHandle:{},find:{},relative:{">":{dir:"parentNode",first:!0}," ":{dir:"parentNode"},"+":{dir:"previousSibling",first:!0},"~":{dir:"previousSibling"}},preFilter:{ATTR:function(a){return a[1]=a[1].replace(cb,db),a[3]=(a[3]||a[4]||a[5]||"").replace(cb,db),"~="===a[2]&&(a[3]=" "+a[3]+" "),a.slice(0,4)},CHILD:function(a){return a[1]=a[1].toLowerCase(),"nth"===a[1].slice(0,3)?(a[3]||fb.error(a[0]),a[4]=+(a[4]?a[5]+(a[6]||1):2*("even"===a[3]||"odd"===a[3])),a[5]=+(a[7]+a[8]||"odd"===a[3])):a[3]&&fb.error(a[0]),a},PSEUDO:function(a){var b,c=!a[6]&&a[2];return X.CHILD.test(a[0])?null:(a[3]?a[2]=a[4]||a[5]||"":c&&V.test(c)&&(b=g(c,!0))&&(b=c.indexOf(")",c.length-b)-c.length)&&(a[0]=a[0].slice(0,b),a[2]=c.slice(0,b)),a.slice(0,3))}},filter:{TAG:function(a){var b=a.replace(cb,db).toLowerCase();return"*"===a?function(){return!0}:function(a){return a.nodeName&&a.nodeName.toLowerCase()===b}},CLASS:function(a){var b=y[a+" "];return b||(b=new RegExp("(^|"+M+")"+a+"("+M+"|$)"))&&y(a,function(a){return b.test("string"==typeof a.className&&a.className||typeof a.getAttribute!==C&&a.getAttribute("class")||"")})},ATTR:function(a,b,c){return function(d){var e=fb.attr(d,a);return null==e?"!="===b:b?(e+="","="===b?e===c:"!="===b?e!==c:"^="===b?c&&0===e.indexOf(c):"*="===b?c&&e.indexOf(c)>-1:"$="===b?c&&e.slice(-c.length)===c:"~="===b?(" "+e+" ").indexOf(c)>-1:"|="===b?e===c||e.slice(0,c.length+1)===c+"-":!1):!0}},CHILD:function(a,b,c,d,e){var f="nth"!==a.slice(0,3),g="last"!==a.slice(-4),h="of-type"===b;return 1===d&&0===e?function(a){return!!a.parentNode}:function(b,c,i){var j,k,l,m,n,o,p=f!==g?"nextSibling":"previousSibling",q=b.parentNode,r=h&&b.nodeName.toLowerCase(),s=!i&&!h;if(q){if(f){while(p){l=b;while(l=l[p])if(h?l.nodeName.toLowerCase()===r:1===l.nodeType)return!1;o=p="only"===a&&!o&&"nextSibling"}return!0}if(o=[g?q.firstChild:q.lastChild],g&&s){k=q[u]||(q[u]={}),j=k[a]||[],n=j[0]===w&&j[1],m=j[0]===w&&j[2],l=n&&q.childNodes[n];while(l=++n&&l&&l[p]||(m=n=0)||o.pop())if(1===l.nodeType&&++m&&l===b){k[a]=[w,n,m];break}}else if(s&&(j=(b[u]||(b[u]={}))[a])&&j[0]===w)m=j[1];else while(l=++n&&l&&l[p]||(m=n=0)||o.pop())if((h?l.nodeName.toLowerCase()===r:1===l.nodeType)&&++m&&(s&&((l[u]||(l[u]={}))[a]=[w,m]),l===b))break;return m-=e,m===d||m%d===0&&m/d>=0}}},PSEUDO:function(a,b){var c,e=d.pseudos[a]||d.setFilters[a.toLowerCase()]||fb.error("unsupported pseudo: "+a);return e[u]?e(b):e.length>1?(c=[a,a,"",b],d.setFilters.hasOwnProperty(a.toLowerCase())?hb(function(a,c){var d,f=e(a,b),g=f.length;while(g--)d=K.call(a,f[g]),a[d]=!(c[d]=f[g])}):function(a){return e(a,0,c)}):e}},pseudos:{not:hb(function(a){var b=[],c=[],d=h(a.replace(R,"$1"));return d[u]?hb(function(a,b,c,e){var f,g=d(a,null,e,[]),h=a.length;while(h--)(f=g[h])&&(a[h]=!(b[h]=f))}):function(a,e,f){return b[0]=a,d(b,null,f,c),!c.pop()}}),has:hb(function(a){return function(b){return fb(a,b).length>0}}),contains:hb(function(a){return function(b){return(b.textContent||b.innerText||e(b)).indexOf(a)>-1}}),lang:hb(function(a){return W.test(a||"")||fb.error("unsupported lang: "+a),a=a.replace(cb,db).toLowerCase(),function(b){var c;do if(c=p?b.lang:b.getAttribute("xml:lang")||b.getAttribute("lang"))return c=c.toLowerCase(),c===a||0===c.indexOf(a+"-");while((b=b.parentNode)&&1===b.nodeType);return!1}}),target:function(b){var c=a.location&&a.location.hash;return c&&c.slice(1)===b.id},root:function(a){return a===o},focus:function(a){return a===n.activeElement&&(!n.hasFocus||n.hasFocus())&&!!(a.type||a.href||~a.tabIndex)},enabled:function(a){return a.disabled===!1},disabled:function(a){return a.disabled===!0},checked:function(a){var b=a.nodeName.toLowerCase();return"input"===b&&!!a.checked||"option"===b&&!!a.selected},selected:function(a){return a.parentNode&&a.parentNode.selectedIndex,a.selected===!0},empty:function(a){for(a=a.firstChild;a;a=a.nextSibling)if(a.nodeType<6)return!1;return!0},parent:function(a){return!d.pseudos.empty(a)},header:function(a){return Z.test(a.nodeName)},input:function(a){return Y.test(a.nodeName)},button:function(a){var b=a.nodeName.toLowerCase();return"input"===b&&"button"===a.type||"button"===b},text:function(a){var b;return"input"===a.nodeName.toLowerCase()&&"text"===a.type&&(null==(b=a.getAttribute("type"))||"text"===b.toLowerCase())},first:nb(function(){return[0]}),last:nb(function(a,b){return[b-1]}),eq:nb(function(a,b,c){return[0>c?c+b:c]}),even:nb(function(a,b){for(var c=0;b>c;c+=2)a.push(c);return a}),odd:nb(function(a,b){for(var c=1;b>c;c+=2)a.push(c);return a}),lt:nb(function(a,b,c){for(var d=0>c?c+b:c;--d>=0;)a.push(d);return a}),gt:nb(function(a,b,c){for(var d=0>c?c+b:c;++db;b++)d+=a[b].value;return d}function rb(a,b,c){var d=b.dir,e=c&&"parentNode"===d,f=x++;return b.first?function(b,c,f){while(b=b[d])if(1===b.nodeType||e)return a(b,c,f)}:function(b,c,g){var h,i,j=[w,f];if(g){while(b=b[d])if((1===b.nodeType||e)&&a(b,c,g))return!0}else while(b=b[d])if(1===b.nodeType||e){if(i=b[u]||(b[u]={}),(h=i[d])&&h[0]===w&&h[1]===f)return j[2]=h[2];if(i[d]=j,j[2]=a(b,c,g))return!0}}}function sb(a){return a.length>1?function(b,c,d){var e=a.length;while(e--)if(!a[e](b,c,d))return!1;return!0}:a[0]}function tb(a,b,c){for(var d=0,e=b.length;e>d;d++)fb(a,b[d],c);return c}function ub(a,b,c,d,e){for(var f,g=[],h=0,i=a.length,j=null!=b;i>h;h++)(f=a[h])&&(!c||c(f,d,e))&&(g.push(f),j&&b.push(h));return g}function vb(a,b,c,d,e,f){return d&&!d[u]&&(d=vb(d)),e&&!e[u]&&(e=vb(e,f)),hb(function(f,g,h,i){var j,k,l,m=[],n=[],o=g.length,p=f||tb(b||"*",h.nodeType?[h]:h,[]),q=!a||!f&&b?p:ub(p,m,a,h,i),r=c?e||(f?a:o||d)?[]:g:q;if(c&&c(q,r,h,i),d){j=ub(r,n),d(j,[],h,i),k=j.length;while(k--)(l=j[k])&&(r[n[k]]=!(q[n[k]]=l))}if(f){if(e||a){if(e){j=[],k=r.length;while(k--)(l=r[k])&&j.push(q[k]=l);e(null,r=[],j,i)}k=r.length;while(k--)(l=r[k])&&(j=e?K.call(f,l):m[k])>-1&&(f[j]=!(g[j]=l))}}else r=ub(r===g?r.splice(o,r.length):r),e?e(null,g,r,i):I.apply(g,r)})}function wb(a){for(var b,c,e,f=a.length,g=d.relative[a[0].type],h=g||d.relative[" "],i=g?1:0,k=rb(function(a){return a===b},h,!0),l=rb(function(a){return K.call(b,a)>-1},h,!0),m=[function(a,c,d){return!g&&(d||c!==j)||((b=c).nodeType?k(a,c,d):l(a,c,d))}];f>i;i++)if(c=d.relative[a[i].type])m=[rb(sb(m),c)];else{if(c=d.filter[a[i].type].apply(null,a[i].matches),c[u]){for(e=++i;f>e;e++)if(d.relative[a[e].type])break;return vb(i>1&&sb(m),i>1&&qb(a.slice(0,i-1).concat({value:" "===a[i-2].type?"*":""})).replace(R,"$1"),c,e>i&&wb(a.slice(i,e)),f>e&&wb(a=a.slice(e)),f>e&&qb(a))}m.push(c)}return sb(m)}function xb(a,b){var c=b.length>0,e=a.length>0,f=function(f,g,h,i,k){var l,m,o,p=0,q="0",r=f&&[],s=[],t=j,u=f||e&&d.find.TAG("*",k),v=w+=null==t?1:Math.random()||.1,x=u.length;for(k&&(j=g!==n&&g);q!==x&&null!=(l=u[q]);q++){if(e&&l){m=0;while(o=a[m++])if(o(l,g,h)){i.push(l);break}k&&(w=v)}c&&((l=!o&&l)&&p--,f&&r.push(l))}if(p+=q,c&&q!==p){m=0;while(o=b[m++])o(r,s,g,h);if(f){if(p>0)while(q--)r[q]||s[q]||(s[q]=G.call(i));s=ub(s)}I.apply(i,s),k&&!f&&s.length>0&&p+b.length>1&&fb.uniqueSort(i)}return k&&(w=v,j=t),r};return c?hb(f):f}return h=fb.compile=function(a,b){var c,d=[],e=[],f=A[a+" "];if(!f){b||(b=g(a)),c=b.length;while(c--)f=wb(b[c]),f[u]?d.push(f):e.push(f);f=A(a,xb(e,d)),f.selector=a}return f},i=fb.select=function(a,b,e,f){var i,j,k,l,m,n="function"==typeof a&&a,o=!f&&g(a=n.selector||a);if(e=e||[],1===o.length){if(j=o[0]=o[0].slice(0),j.length>2&&"ID"===(k=j[0]).type&&c.getById&&9===b.nodeType&&p&&d.relative[j[1].type]){if(b=(d.find.ID(k.matches[0].replace(cb,db),b)||[])[0],!b)return e;n&&(b=b.parentNode),a=a.slice(j.shift().value.length)}i=X.needsContext.test(a)?0:j.length;while(i--){if(k=j[i],d.relative[l=k.type])break;if((m=d.find[l])&&(f=m(k.matches[0].replace(cb,db),ab.test(j[0].type)&&ob(b.parentNode)||b))){if(j.splice(i,1),a=f.length&&qb(j),!a)return I.apply(e,f),e;break}}}return(n||h(a,o))(f,b,!p,e,ab.test(a)&&ob(b.parentNode)||b),e},c.sortStable=u.split("").sort(B).join("")===u,c.detectDuplicates=!!l,m(),c.sortDetached=ib(function(a){return 1&a.compareDocumentPosition(n.createElement("div"))}),ib(function(a){return a.innerHTML="","#"===a.firstChild.getAttribute("href")})||jb("type|href|height|width",function(a,b,c){return c?void 0:a.getAttribute(b,"type"===b.toLowerCase()?1:2)}),c.attributes&&ib(function(a){return a.innerHTML="",a.firstChild.setAttribute("value",""),""===a.firstChild.getAttribute("value")})||jb("value",function(a,b,c){return c||"input"!==a.nodeName.toLowerCase()?void 0:a.defaultValue}),ib(function(a){return null==a.getAttribute("disabled")})||jb(L,function(a,b,c){var d;return c?void 0:a[b]===!0?b.toLowerCase():(d=a.getAttributeNode(b))&&d.specified?d.value:null}),fb}(a);m.find=s,m.expr=s.selectors,m.expr[":"]=m.expr.pseudos,m.unique=s.uniqueSort,m.text=s.getText,m.isXMLDoc=s.isXML,m.contains=s.contains;var t=m.expr.match.needsContext,u=/^<(\w+)\s*\/?>(?:<\/\1>|)$/,v=/^.[^:#\[\.,]*$/;function w(a,b,c){if(m.isFunction(b))return m.grep(a,function(a,d){return!!b.call(a,d,a)!==c});if(b.nodeType)return m.grep(a,function(a){return a===b!==c});if("string"==typeof b){if(v.test(b))return m.filter(b,a,c);b=m.filter(b,a)}return m.grep(a,function(a){return m.inArray(a,b)>=0!==c})}m.filter=function(a,b,c){var d=b[0];return c&&(a=":not("+a+")"),1===b.length&&1===d.nodeType?m.find.matchesSelector(d,a)?[d]:[]:m.find.matches(a,m.grep(b,function(a){return 1===a.nodeType}))},m.fn.extend({find:function(a){var b,c=[],d=this,e=d.length;if("string"!=typeof a)return this.pushStack(m(a).filter(function(){for(b=0;e>b;b++)if(m.contains(d[b],this))return!0}));for(b=0;e>b;b++)m.find(a,d[b],c);return c=this.pushStack(e>1?m.unique(c):c),c.selector=this.selector?this.selector+" "+a:a,c},filter:function(a){return this.pushStack(w(this,a||[],!1))},not:function(a){return this.pushStack(w(this,a||[],!0))},is:function(a){return!!w(this,"string"==typeof a&&t.test(a)?m(a):a||[],!1).length}});var x,y=a.document,z=/^(?:\s*(<[\w\W]+>)[^>]*|#([\w-]*))$/,A=m.fn.init=function(a,b){var c,d;if(!a)return this;if("string"==typeof a){if(c="<"===a.charAt(0)&&">"===a.charAt(a.length-1)&&a.length>=3?[null,a,null]:z.exec(a),!c||!c[1]&&b)return!b||b.jquery?(b||x).find(a):this.constructor(b).find(a);if(c[1]){if(b=b instanceof m?b[0]:b,m.merge(this,m.parseHTML(c[1],b&&b.nodeType?b.ownerDocument||b:y,!0)),u.test(c[1])&&m.isPlainObject(b))for(c in b)m.isFunction(this[c])?this[c](b[c]):this.attr(c,b[c]);return this}if(d=y.getElementById(c[2]),d&&d.parentNode){if(d.id!==c[2])return x.find(a);this.length=1,this[0]=d}return this.context=y,this.selector=a,this}return a.nodeType?(this.context=this[0]=a,this.length=1,this):m.isFunction(a)?"undefined"!=typeof x.ready?x.ready(a):a(m):(void 0!==a.selector&&(this.selector=a.selector,this.context=a.context),m.makeArray(a,this))};A.prototype=m.fn,x=m(y);var B=/^(?:parents|prev(?:Until|All))/,C={children:!0,contents:!0,next:!0,prev:!0};m.extend({dir:function(a,b,c){var d=[],e=a[b];while(e&&9!==e.nodeType&&(void 0===c||1!==e.nodeType||!m(e).is(c)))1===e.nodeType&&d.push(e),e=e[b];return d},sibling:function(a,b){for(var c=[];a;a=a.nextSibling)1===a.nodeType&&a!==b&&c.push(a);return c}}),m.fn.extend({has:function(a){var b,c=m(a,this),d=c.length;return this.filter(function(){for(b=0;d>b;b++)if(m.contains(this,c[b]))return!0})},closest:function(a,b){for(var c,d=0,e=this.length,f=[],g=t.test(a)||"string"!=typeof a?m(a,b||this.context):0;e>d;d++)for(c=this[d];c&&c!==b;c=c.parentNode)if(c.nodeType<11&&(g?g.index(c)>-1:1===c.nodeType&&m.find.matchesSelector(c,a))){f.push(c);break}return this.pushStack(f.length>1?m.unique(f):f)},index:function(a){return a?"string"==typeof a?m.inArray(this[0],m(a)):m.inArray(a.jquery?a[0]:a,this):this[0]&&this[0].parentNode?this.first().prevAll().length:-1},add:function(a,b){return this.pushStack(m.unique(m.merge(this.get(),m(a,b))))},addBack:function(a){return this.add(null==a?this.prevObject:this.prevObject.filter(a))}});function D(a,b){do a=a[b];while(a&&1!==a.nodeType);return a}m.each({parent:function(a){var b=a.parentNode;return b&&11!==b.nodeType?b:null},parents:function(a){return m.dir(a,"parentNode")},parentsUntil:function(a,b,c){return m.dir(a,"parentNode",c)},next:function(a){return D(a,"nextSibling")},prev:function(a){return D(a,"previousSibling")},nextAll:function(a){return m.dir(a,"nextSibling")},prevAll:function(a){return m.dir(a,"previousSibling")},nextUntil:function(a,b,c){return m.dir(a,"nextSibling",c)},prevUntil:function(a,b,c){return m.dir(a,"previousSibling",c)},siblings:function(a){return m.sibling((a.parentNode||{}).firstChild,a)},children:function(a){return m.sibling(a.firstChild)},contents:function(a){return m.nodeName(a,"iframe")?a.contentDocument||a.contentWindow.document:m.merge([],a.childNodes)}},function(a,b){m.fn[a]=function(c,d){var e=m.map(this,b,c);return"Until"!==a.slice(-5)&&(d=c),d&&"string"==typeof d&&(e=m.filter(d,e)),this.length>1&&(C[a]||(e=m.unique(e)),B.test(a)&&(e=e.reverse())),this.pushStack(e)}});var E=/\S+/g,F={};function G(a){var b=F[a]={};return m.each(a.match(E)||[],function(a,c){b[c]=!0}),b}m.Callbacks=function(a){a="string"==typeof a?F[a]||G(a):m.extend({},a);var b,c,d,e,f,g,h=[],i=!a.once&&[],j=function(l){for(c=a.memory&&l,d=!0,f=g||0,g=0,e=h.length,b=!0;h&&e>f;f++)if(h[f].apply(l[0],l[1])===!1&&a.stopOnFalse){c=!1;break}b=!1,h&&(i?i.length&&j(i.shift()):c?h=[]:k.disable())},k={add:function(){if(h){var d=h.length;!function f(b){m.each(b,function(b,c){var d=m.type(c);"function"===d?a.unique&&k.has(c)||h.push(c):c&&c.length&&"string"!==d&&f(c)})}(arguments),b?e=h.length:c&&(g=d,j(c))}return this},remove:function(){return h&&m.each(arguments,function(a,c){var d;while((d=m.inArray(c,h,d))>-1)h.splice(d,1),b&&(e>=d&&e--,f>=d&&f--)}),this},has:function(a){return a?m.inArray(a,h)>-1:!(!h||!h.length)},empty:function(){return h=[],e=0,this},disable:function(){return h=i=c=void 0,this},disabled:function(){return!h},lock:function(){return i=void 0,c||k.disable(),this},locked:function(){return!i},fireWith:function(a,c){return!h||d&&!i||(c=c||[],c=[a,c.slice?c.slice():c],b?i.push(c):j(c)),this},fire:function(){return k.fireWith(this,arguments),this},fired:function(){return!!d}};return k},m.extend({Deferred:function(a){var b=[["resolve","done",m.Callbacks("once memory"),"resolved"],["reject","fail",m.Callbacks("once memory"),"rejected"],["notify","progress",m.Callbacks("memory")]],c="pending",d={state:function(){return c},always:function(){return e.done(arguments).fail(arguments),this},then:function(){var a=arguments;return m.Deferred(function(c){m.each(b,function(b,f){var g=m.isFunction(a[b])&&a[b];e[f[1]](function(){var a=g&&g.apply(this,arguments);a&&m.isFunction(a.promise)?a.promise().done(c.resolve).fail(c.reject).progress(c.notify):c[f[0]+"With"](this===d?c.promise():this,g?[a]:arguments)})}),a=null}).promise()},promise:function(a){return null!=a?m.extend(a,d):d}},e={};return d.pipe=d.then,m.each(b,function(a,f){var g=f[2],h=f[3];d[f[1]]=g.add,h&&g.add(function(){c=h},b[1^a][2].disable,b[2][2].lock),e[f[0]]=function(){return e[f[0]+"With"](this===e?d:this,arguments),this},e[f[0]+"With"]=g.fireWith}),d.promise(e),a&&a.call(e,e),e},when:function(a){var b=0,c=d.call(arguments),e=c.length,f=1!==e||a&&m.isFunction(a.promise)?e:0,g=1===f?a:m.Deferred(),h=function(a,b,c){return function(e){b[a]=this,c[a]=arguments.length>1?d.call(arguments):e,c===i?g.notifyWith(b,c):--f||g.resolveWith(b,c)}},i,j,k;if(e>1)for(i=new Array(e),j=new Array(e),k=new Array(e);e>b;b++)c[b]&&m.isFunction(c[b].promise)?c[b].promise().done(h(b,k,c)).fail(g.reject).progress(h(b,j,i)):--f;return f||g.resolveWith(k,c),g.promise()}});var H;m.fn.ready=function(a){return m.ready.promise().done(a),this},m.extend({isReady:!1,readyWait:1,holdReady:function(a){a?m.readyWait++:m.ready(!0)},ready:function(a){if(a===!0?!--m.readyWait:!m.isReady){if(!y.body)return setTimeout(m.ready);m.isReady=!0,a!==!0&&--m.readyWait>0||(H.resolveWith(y,[m]),m.fn.triggerHandler&&(m(y).triggerHandler("ready"),m(y).off("ready")))}}});function I(){y.addEventListener?(y.removeEventListener("DOMContentLoaded",J,!1),a.removeEventListener("load",J,!1)):(y.detachEvent("onreadystatechange",J),a.detachEvent("onload",J))}function J(){(y.addEventListener||"load"===event.type||"complete"===y.readyState)&&(I(),m.ready())}m.ready.promise=function(b){if(!H)if(H=m.Deferred(),"complete"===y.readyState)setTimeout(m.ready);else if(y.addEventListener)y.addEventListener("DOMContentLoaded",J,!1),a.addEventListener("load",J,!1);else{y.attachEvent("onreadystatechange",J),a.attachEvent("onload",J);var c=!1;try{c=null==a.frameElement&&y.documentElement}catch(d){}c&&c.doScroll&&!function e(){if(!m.isReady){try{c.doScroll("left")}catch(a){return setTimeout(e,50)}I(),m.ready()}}()}return H.promise(b)};var K="undefined",L;for(L in m(k))break;k.ownLast="0"!==L,k.inlineBlockNeedsLayout=!1,m(function(){var a,b,c,d;c=y.getElementsByTagName("body")[0],c&&c.style&&(b=y.createElement("div"),d=y.createElement("div"),d.style.cssText="position:absolute;border:0;width:0;height:0;top:0;left:-9999px",c.appendChild(d).appendChild(b),typeof b.style.zoom!==K&&(b.style.cssText="display:inline;margin:0;border:0;padding:1px;width:1px;zoom:1",k.inlineBlockNeedsLayout=a=3===b.offsetWidth,a&&(c.style.zoom=1)),c.removeChild(d))}),function(){var a=y.createElement("div");if(null==k.deleteExpando){k.deleteExpando=!0;try{delete a.test}catch(b){k.deleteExpando=!1}}a=null}(),m.acceptData=function(a){var b=m.noData[(a.nodeName+" ").toLowerCase()],c=+a.nodeType||1;return 1!==c&&9!==c?!1:!b||b!==!0&&a.getAttribute("classid")===b};var M=/^(?:\{[\w\W]*\}|\[[\w\W]*\])$/,N=/([A-Z])/g;function O(a,b,c){if(void 0===c&&1===a.nodeType){var d="data-"+b.replace(N,"-$1").toLowerCase();if(c=a.getAttribute(d),"string"==typeof c){try{c="true"===c?!0:"false"===c?!1:"null"===c?null:+c+""===c?+c:M.test(c)?m.parseJSON(c):c}catch(e){}m.data(a,b,c)}else c=void 0}return c}function P(a){var b;for(b in a)if(("data"!==b||!m.isEmptyObject(a[b]))&&"toJSON"!==b)return!1;return!0}function Q(a,b,d,e){if(m.acceptData(a)){var f,g,h=m.expando,i=a.nodeType,j=i?m.cache:a,k=i?a[h]:a[h]&&h; -if(k&&j[k]&&(e||j[k].data)||void 0!==d||"string"!=typeof b)return k||(k=i?a[h]=c.pop()||m.guid++:h),j[k]||(j[k]=i?{}:{toJSON:m.noop}),("object"==typeof b||"function"==typeof b)&&(e?j[k]=m.extend(j[k],b):j[k].data=m.extend(j[k].data,b)),g=j[k],e||(g.data||(g.data={}),g=g.data),void 0!==d&&(g[m.camelCase(b)]=d),"string"==typeof b?(f=g[b],null==f&&(f=g[m.camelCase(b)])):f=g,f}}function R(a,b,c){if(m.acceptData(a)){var d,e,f=a.nodeType,g=f?m.cache:a,h=f?a[m.expando]:m.expando;if(g[h]){if(b&&(d=c?g[h]:g[h].data)){m.isArray(b)?b=b.concat(m.map(b,m.camelCase)):b in d?b=[b]:(b=m.camelCase(b),b=b in d?[b]:b.split(" ")),e=b.length;while(e--)delete d[b[e]];if(c?!P(d):!m.isEmptyObject(d))return}(c||(delete g[h].data,P(g[h])))&&(f?m.cleanData([a],!0):k.deleteExpando||g!=g.window?delete g[h]:g[h]=null)}}}m.extend({cache:{},noData:{"applet ":!0,"embed ":!0,"object ":"clsid:D27CDB6E-AE6D-11cf-96B8-444553540000"},hasData:function(a){return a=a.nodeType?m.cache[a[m.expando]]:a[m.expando],!!a&&!P(a)},data:function(a,b,c){return Q(a,b,c)},removeData:function(a,b){return R(a,b)},_data:function(a,b,c){return Q(a,b,c,!0)},_removeData:function(a,b){return R(a,b,!0)}}),m.fn.extend({data:function(a,b){var c,d,e,f=this[0],g=f&&f.attributes;if(void 0===a){if(this.length&&(e=m.data(f),1===f.nodeType&&!m._data(f,"parsedAttrs"))){c=g.length;while(c--)g[c]&&(d=g[c].name,0===d.indexOf("data-")&&(d=m.camelCase(d.slice(5)),O(f,d,e[d])));m._data(f,"parsedAttrs",!0)}return e}return"object"==typeof a?this.each(function(){m.data(this,a)}):arguments.length>1?this.each(function(){m.data(this,a,b)}):f?O(f,a,m.data(f,a)):void 0},removeData:function(a){return this.each(function(){m.removeData(this,a)})}}),m.extend({queue:function(a,b,c){var d;return a?(b=(b||"fx")+"queue",d=m._data(a,b),c&&(!d||m.isArray(c)?d=m._data(a,b,m.makeArray(c)):d.push(c)),d||[]):void 0},dequeue:function(a,b){b=b||"fx";var c=m.queue(a,b),d=c.length,e=c.shift(),f=m._queueHooks(a,b),g=function(){m.dequeue(a,b)};"inprogress"===e&&(e=c.shift(),d--),e&&("fx"===b&&c.unshift("inprogress"),delete f.stop,e.call(a,g,f)),!d&&f&&f.empty.fire()},_queueHooks:function(a,b){var c=b+"queueHooks";return m._data(a,c)||m._data(a,c,{empty:m.Callbacks("once memory").add(function(){m._removeData(a,b+"queue"),m._removeData(a,c)})})}}),m.fn.extend({queue:function(a,b){var c=2;return"string"!=typeof a&&(b=a,a="fx",c--),arguments.lengthh;h++)b(a[h],c,g?d:d.call(a[h],h,b(a[h],c)));return e?a:j?b.call(a):i?b(a[0],c):f},W=/^(?:checkbox|radio)$/i;!function(){var a=y.createElement("input"),b=y.createElement("div"),c=y.createDocumentFragment();if(b.innerHTML="
    a",k.leadingWhitespace=3===b.firstChild.nodeType,k.tbody=!b.getElementsByTagName("tbody").length,k.htmlSerialize=!!b.getElementsByTagName("link").length,k.html5Clone="<:nav>"!==y.createElement("nav").cloneNode(!0).outerHTML,a.type="checkbox",a.checked=!0,c.appendChild(a),k.appendChecked=a.checked,b.innerHTML="",k.noCloneChecked=!!b.cloneNode(!0).lastChild.defaultValue,c.appendChild(b),b.innerHTML="",k.checkClone=b.cloneNode(!0).cloneNode(!0).lastChild.checked,k.noCloneEvent=!0,b.attachEvent&&(b.attachEvent("onclick",function(){k.noCloneEvent=!1}),b.cloneNode(!0).click()),null==k.deleteExpando){k.deleteExpando=!0;try{delete b.test}catch(d){k.deleteExpando=!1}}}(),function(){var b,c,d=y.createElement("div");for(b in{submit:!0,change:!0,focusin:!0})c="on"+b,(k[b+"Bubbles"]=c in a)||(d.setAttribute(c,"t"),k[b+"Bubbles"]=d.attributes[c].expando===!1);d=null}();var X=/^(?:input|select|textarea)$/i,Y=/^key/,Z=/^(?:mouse|pointer|contextmenu)|click/,$=/^(?:focusinfocus|focusoutblur)$/,_=/^([^.]*)(?:\.(.+)|)$/;function ab(){return!0}function bb(){return!1}function cb(){try{return y.activeElement}catch(a){}}m.event={global:{},add:function(a,b,c,d,e){var f,g,h,i,j,k,l,n,o,p,q,r=m._data(a);if(r){c.handler&&(i=c,c=i.handler,e=i.selector),c.guid||(c.guid=m.guid++),(g=r.events)||(g=r.events={}),(k=r.handle)||(k=r.handle=function(a){return typeof m===K||a&&m.event.triggered===a.type?void 0:m.event.dispatch.apply(k.elem,arguments)},k.elem=a),b=(b||"").match(E)||[""],h=b.length;while(h--)f=_.exec(b[h])||[],o=q=f[1],p=(f[2]||"").split(".").sort(),o&&(j=m.event.special[o]||{},o=(e?j.delegateType:j.bindType)||o,j=m.event.special[o]||{},l=m.extend({type:o,origType:q,data:d,handler:c,guid:c.guid,selector:e,needsContext:e&&m.expr.match.needsContext.test(e),namespace:p.join(".")},i),(n=g[o])||(n=g[o]=[],n.delegateCount=0,j.setup&&j.setup.call(a,d,p,k)!==!1||(a.addEventListener?a.addEventListener(o,k,!1):a.attachEvent&&a.attachEvent("on"+o,k))),j.add&&(j.add.call(a,l),l.handler.guid||(l.handler.guid=c.guid)),e?n.splice(n.delegateCount++,0,l):n.push(l),m.event.global[o]=!0);a=null}},remove:function(a,b,c,d,e){var f,g,h,i,j,k,l,n,o,p,q,r=m.hasData(a)&&m._data(a);if(r&&(k=r.events)){b=(b||"").match(E)||[""],j=b.length;while(j--)if(h=_.exec(b[j])||[],o=q=h[1],p=(h[2]||"").split(".").sort(),o){l=m.event.special[o]||{},o=(d?l.delegateType:l.bindType)||o,n=k[o]||[],h=h[2]&&new RegExp("(^|\\.)"+p.join("\\.(?:.*\\.|)")+"(\\.|$)"),i=f=n.length;while(f--)g=n[f],!e&&q!==g.origType||c&&c.guid!==g.guid||h&&!h.test(g.namespace)||d&&d!==g.selector&&("**"!==d||!g.selector)||(n.splice(f,1),g.selector&&n.delegateCount--,l.remove&&l.remove.call(a,g));i&&!n.length&&(l.teardown&&l.teardown.call(a,p,r.handle)!==!1||m.removeEvent(a,o,r.handle),delete k[o])}else for(o in k)m.event.remove(a,o+b[j],c,d,!0);m.isEmptyObject(k)&&(delete r.handle,m._removeData(a,"events"))}},trigger:function(b,c,d,e){var f,g,h,i,k,l,n,o=[d||y],p=j.call(b,"type")?b.type:b,q=j.call(b,"namespace")?b.namespace.split("."):[];if(h=l=d=d||y,3!==d.nodeType&&8!==d.nodeType&&!$.test(p+m.event.triggered)&&(p.indexOf(".")>=0&&(q=p.split("."),p=q.shift(),q.sort()),g=p.indexOf(":")<0&&"on"+p,b=b[m.expando]?b:new m.Event(p,"object"==typeof b&&b),b.isTrigger=e?2:3,b.namespace=q.join("."),b.namespace_re=b.namespace?new RegExp("(^|\\.)"+q.join("\\.(?:.*\\.|)")+"(\\.|$)"):null,b.result=void 0,b.target||(b.target=d),c=null==c?[b]:m.makeArray(c,[b]),k=m.event.special[p]||{},e||!k.trigger||k.trigger.apply(d,c)!==!1)){if(!e&&!k.noBubble&&!m.isWindow(d)){for(i=k.delegateType||p,$.test(i+p)||(h=h.parentNode);h;h=h.parentNode)o.push(h),l=h;l===(d.ownerDocument||y)&&o.push(l.defaultView||l.parentWindow||a)}n=0;while((h=o[n++])&&!b.isPropagationStopped())b.type=n>1?i:k.bindType||p,f=(m._data(h,"events")||{})[b.type]&&m._data(h,"handle"),f&&f.apply(h,c),f=g&&h[g],f&&f.apply&&m.acceptData(h)&&(b.result=f.apply(h,c),b.result===!1&&b.preventDefault());if(b.type=p,!e&&!b.isDefaultPrevented()&&(!k._default||k._default.apply(o.pop(),c)===!1)&&m.acceptData(d)&&g&&d[p]&&!m.isWindow(d)){l=d[g],l&&(d[g]=null),m.event.triggered=p;try{d[p]()}catch(r){}m.event.triggered=void 0,l&&(d[g]=l)}return b.result}},dispatch:function(a){a=m.event.fix(a);var b,c,e,f,g,h=[],i=d.call(arguments),j=(m._data(this,"events")||{})[a.type]||[],k=m.event.special[a.type]||{};if(i[0]=a,a.delegateTarget=this,!k.preDispatch||k.preDispatch.call(this,a)!==!1){h=m.event.handlers.call(this,a,j),b=0;while((f=h[b++])&&!a.isPropagationStopped()){a.currentTarget=f.elem,g=0;while((e=f.handlers[g++])&&!a.isImmediatePropagationStopped())(!a.namespace_re||a.namespace_re.test(e.namespace))&&(a.handleObj=e,a.data=e.data,c=((m.event.special[e.origType]||{}).handle||e.handler).apply(f.elem,i),void 0!==c&&(a.result=c)===!1&&(a.preventDefault(),a.stopPropagation()))}return k.postDispatch&&k.postDispatch.call(this,a),a.result}},handlers:function(a,b){var c,d,e,f,g=[],h=b.delegateCount,i=a.target;if(h&&i.nodeType&&(!a.button||"click"!==a.type))for(;i!=this;i=i.parentNode||this)if(1===i.nodeType&&(i.disabled!==!0||"click"!==a.type)){for(e=[],f=0;h>f;f++)d=b[f],c=d.selector+" ",void 0===e[c]&&(e[c]=d.needsContext?m(c,this).index(i)>=0:m.find(c,this,null,[i]).length),e[c]&&e.push(d);e.length&&g.push({elem:i,handlers:e})}return h]","i"),hb=/^\s+/,ib=/<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/gi,jb=/<([\w:]+)/,kb=/\s*$/g,rb={option:[1,""],legend:[1,"
    ","
    "],area:[1,"",""],param:[1,"",""],thead:[1,"","
    "],tr:[2,"","
    "],col:[2,"","
    "],td:[3,"","
    "],_default:k.htmlSerialize?[0,"",""]:[1,"X
    ","
    "]},sb=db(y),tb=sb.appendChild(y.createElement("div"));rb.optgroup=rb.option,rb.tbody=rb.tfoot=rb.colgroup=rb.caption=rb.thead,rb.th=rb.td;function ub(a,b){var c,d,e=0,f=typeof a.getElementsByTagName!==K?a.getElementsByTagName(b||"*"):typeof a.querySelectorAll!==K?a.querySelectorAll(b||"*"):void 0;if(!f)for(f=[],c=a.childNodes||a;null!=(d=c[e]);e++)!b||m.nodeName(d,b)?f.push(d):m.merge(f,ub(d,b));return void 0===b||b&&m.nodeName(a,b)?m.merge([a],f):f}function vb(a){W.test(a.type)&&(a.defaultChecked=a.checked)}function wb(a,b){return m.nodeName(a,"table")&&m.nodeName(11!==b.nodeType?b:b.firstChild,"tr")?a.getElementsByTagName("tbody")[0]||a.appendChild(a.ownerDocument.createElement("tbody")):a}function xb(a){return a.type=(null!==m.find.attr(a,"type"))+"/"+a.type,a}function yb(a){var b=pb.exec(a.type);return b?a.type=b[1]:a.removeAttribute("type"),a}function zb(a,b){for(var c,d=0;null!=(c=a[d]);d++)m._data(c,"globalEval",!b||m._data(b[d],"globalEval"))}function Ab(a,b){if(1===b.nodeType&&m.hasData(a)){var c,d,e,f=m._data(a),g=m._data(b,f),h=f.events;if(h){delete g.handle,g.events={};for(c in h)for(d=0,e=h[c].length;e>d;d++)m.event.add(b,c,h[c][d])}g.data&&(g.data=m.extend({},g.data))}}function Bb(a,b){var c,d,e;if(1===b.nodeType){if(c=b.nodeName.toLowerCase(),!k.noCloneEvent&&b[m.expando]){e=m._data(b);for(d in e.events)m.removeEvent(b,d,e.handle);b.removeAttribute(m.expando)}"script"===c&&b.text!==a.text?(xb(b).text=a.text,yb(b)):"object"===c?(b.parentNode&&(b.outerHTML=a.outerHTML),k.html5Clone&&a.innerHTML&&!m.trim(b.innerHTML)&&(b.innerHTML=a.innerHTML)):"input"===c&&W.test(a.type)?(b.defaultChecked=b.checked=a.checked,b.value!==a.value&&(b.value=a.value)):"option"===c?b.defaultSelected=b.selected=a.defaultSelected:("input"===c||"textarea"===c)&&(b.defaultValue=a.defaultValue)}}m.extend({clone:function(a,b,c){var d,e,f,g,h,i=m.contains(a.ownerDocument,a);if(k.html5Clone||m.isXMLDoc(a)||!gb.test("<"+a.nodeName+">")?f=a.cloneNode(!0):(tb.innerHTML=a.outerHTML,tb.removeChild(f=tb.firstChild)),!(k.noCloneEvent&&k.noCloneChecked||1!==a.nodeType&&11!==a.nodeType||m.isXMLDoc(a)))for(d=ub(f),h=ub(a),g=0;null!=(e=h[g]);++g)d[g]&&Bb(e,d[g]);if(b)if(c)for(h=h||ub(a),d=d||ub(f),g=0;null!=(e=h[g]);g++)Ab(e,d[g]);else Ab(a,f);return d=ub(f,"script"),d.length>0&&zb(d,!i&&ub(a,"script")),d=h=e=null,f},buildFragment:function(a,b,c,d){for(var e,f,g,h,i,j,l,n=a.length,o=db(b),p=[],q=0;n>q;q++)if(f=a[q],f||0===f)if("object"===m.type(f))m.merge(p,f.nodeType?[f]:f);else if(lb.test(f)){h=h||o.appendChild(b.createElement("div")),i=(jb.exec(f)||["",""])[1].toLowerCase(),l=rb[i]||rb._default,h.innerHTML=l[1]+f.replace(ib,"<$1>")+l[2],e=l[0];while(e--)h=h.lastChild;if(!k.leadingWhitespace&&hb.test(f)&&p.push(b.createTextNode(hb.exec(f)[0])),!k.tbody){f="table"!==i||kb.test(f)?""!==l[1]||kb.test(f)?0:h:h.firstChild,e=f&&f.childNodes.length;while(e--)m.nodeName(j=f.childNodes[e],"tbody")&&!j.childNodes.length&&f.removeChild(j)}m.merge(p,h.childNodes),h.textContent="";while(h.firstChild)h.removeChild(h.firstChild);h=o.lastChild}else p.push(b.createTextNode(f));h&&o.removeChild(h),k.appendChecked||m.grep(ub(p,"input"),vb),q=0;while(f=p[q++])if((!d||-1===m.inArray(f,d))&&(g=m.contains(f.ownerDocument,f),h=ub(o.appendChild(f),"script"),g&&zb(h),c)){e=0;while(f=h[e++])ob.test(f.type||"")&&c.push(f)}return h=null,o},cleanData:function(a,b){for(var d,e,f,g,h=0,i=m.expando,j=m.cache,l=k.deleteExpando,n=m.event.special;null!=(d=a[h]);h++)if((b||m.acceptData(d))&&(f=d[i],g=f&&j[f])){if(g.events)for(e in g.events)n[e]?m.event.remove(d,e):m.removeEvent(d,e,g.handle);j[f]&&(delete j[f],l?delete d[i]:typeof d.removeAttribute!==K?d.removeAttribute(i):d[i]=null,c.push(f))}}}),m.fn.extend({text:function(a){return V(this,function(a){return void 0===a?m.text(this):this.empty().append((this[0]&&this[0].ownerDocument||y).createTextNode(a))},null,a,arguments.length)},append:function(){return this.domManip(arguments,function(a){if(1===this.nodeType||11===this.nodeType||9===this.nodeType){var b=wb(this,a);b.appendChild(a)}})},prepend:function(){return this.domManip(arguments,function(a){if(1===this.nodeType||11===this.nodeType||9===this.nodeType){var b=wb(this,a);b.insertBefore(a,b.firstChild)}})},before:function(){return this.domManip(arguments,function(a){this.parentNode&&this.parentNode.insertBefore(a,this)})},after:function(){return this.domManip(arguments,function(a){this.parentNode&&this.parentNode.insertBefore(a,this.nextSibling)})},remove:function(a,b){for(var c,d=a?m.filter(a,this):this,e=0;null!=(c=d[e]);e++)b||1!==c.nodeType||m.cleanData(ub(c)),c.parentNode&&(b&&m.contains(c.ownerDocument,c)&&zb(ub(c,"script")),c.parentNode.removeChild(c));return this},empty:function(){for(var a,b=0;null!=(a=this[b]);b++){1===a.nodeType&&m.cleanData(ub(a,!1));while(a.firstChild)a.removeChild(a.firstChild);a.options&&m.nodeName(a,"select")&&(a.options.length=0)}return this},clone:function(a,b){return a=null==a?!1:a,b=null==b?a:b,this.map(function(){return m.clone(this,a,b)})},html:function(a){return V(this,function(a){var b=this[0]||{},c=0,d=this.length;if(void 0===a)return 1===b.nodeType?b.innerHTML.replace(fb,""):void 0;if(!("string"!=typeof a||mb.test(a)||!k.htmlSerialize&&gb.test(a)||!k.leadingWhitespace&&hb.test(a)||rb[(jb.exec(a)||["",""])[1].toLowerCase()])){a=a.replace(ib,"<$1>");try{for(;d>c;c++)b=this[c]||{},1===b.nodeType&&(m.cleanData(ub(b,!1)),b.innerHTML=a);b=0}catch(e){}}b&&this.empty().append(a)},null,a,arguments.length)},replaceWith:function(){var a=arguments[0];return this.domManip(arguments,function(b){a=this.parentNode,m.cleanData(ub(this)),a&&a.replaceChild(b,this)}),a&&(a.length||a.nodeType)?this:this.remove()},detach:function(a){return this.remove(a,!0)},domManip:function(a,b){a=e.apply([],a);var c,d,f,g,h,i,j=0,l=this.length,n=this,o=l-1,p=a[0],q=m.isFunction(p);if(q||l>1&&"string"==typeof p&&!k.checkClone&&nb.test(p))return this.each(function(c){var d=n.eq(c);q&&(a[0]=p.call(this,c,d.html())),d.domManip(a,b)});if(l&&(i=m.buildFragment(a,this[0].ownerDocument,!1,this),c=i.firstChild,1===i.childNodes.length&&(i=c),c)){for(g=m.map(ub(i,"script"),xb),f=g.length;l>j;j++)d=i,j!==o&&(d=m.clone(d,!0,!0),f&&m.merge(g,ub(d,"script"))),b.call(this[j],d,j);if(f)for(h=g[g.length-1].ownerDocument,m.map(g,yb),j=0;f>j;j++)d=g[j],ob.test(d.type||"")&&!m._data(d,"globalEval")&&m.contains(h,d)&&(d.src?m._evalUrl&&m._evalUrl(d.src):m.globalEval((d.text||d.textContent||d.innerHTML||"").replace(qb,"")));i=c=null}return this}}),m.each({appendTo:"append",prependTo:"prepend",insertBefore:"before",insertAfter:"after",replaceAll:"replaceWith"},function(a,b){m.fn[a]=function(a){for(var c,d=0,e=[],g=m(a),h=g.length-1;h>=d;d++)c=d===h?this:this.clone(!0),m(g[d])[b](c),f.apply(e,c.get());return this.pushStack(e)}});var Cb,Db={};function Eb(b,c){var d,e=m(c.createElement(b)).appendTo(c.body),f=a.getDefaultComputedStyle&&(d=a.getDefaultComputedStyle(e[0]))?d.display:m.css(e[0],"display");return e.detach(),f}function Fb(a){var b=y,c=Db[a];return c||(c=Eb(a,b),"none"!==c&&c||(Cb=(Cb||m("