2017-02-15 4 views
2

Я кодирую приложение для Android, которое использует API Google Fit для подключения к полосе Bluetooth-bluetooth с целью сбора информации о частоте сердечных сокращений с датчика. Вот функции, которые я использую:Google Fit API не получает данные из браслета Bluetooth (SWR12)

В приложении основной деятельности:

@Override 
protected void onCreate(Bundle savedInstanceState) { 
if (!checkPermissions()) { 
      requestPermissions(); 
     } 

     if (!checkPermissionsBody()) { 
      requestPermissionsBody(); 

Разрешение запроса функции:

// Now we need a function to check permissions 
    private boolean checkPermissions() { 
     int permissionState = ActivityCompat.checkSelfPermission(this, 
       Manifest.permission.ACCESS_FINE_LOCATION); 
     return permissionState == PackageManager.PERMISSION_GRANTED; 
    } 

    // Now we need a function to check permissions body sensors 
    private boolean checkPermissionsBody() { 
     int permissionState = ActivityCompat.checkSelfPermission(this, 
       Manifest.permission.BODY_SENSORS); 
     return permissionState == PackageManager.PERMISSION_GRANTED; 
    } 


    // If permissions are not given, we need to request permissions 
    private void requestPermissions() { 
     Log.d(TAG,"getting permissions"); 
     boolean shouldProvideRationale = 
       ActivityCompat.shouldShowRequestPermissionRationale(this, 
         Manifest.permission.ACCESS_FINE_LOCATION); 
     Log.d(TAG,String.valueOf(Manifest.permission.ACCESS_FINE_LOCATION)); 
     // Provide an additional rationale to the user. This would happen if the user denied the 
     // request previously, but didn't check the "Don't ask again" checkbox. 
     if (shouldProvideRationale) { 
      Log.i(TAG, "Displaying permission rationale to provide additional context."); 
      Snackbar.make(
        findViewById(R.id.activity_main), 
        R.string.permission_rationale, 
        Snackbar.LENGTH_INDEFINITE) 
        .setAction(R.string.ok, new View.OnClickListener() { 
         @Override 
         public void onClick(View view) { 
          // Request permission 
          ActivityCompat.requestPermissions(MainActivity.this, 
            new String[]{Manifest.permission.ACCESS_FINE_LOCATION}, 
            REQUEST_PERMISSIONS_REQUEST_CODE); 
         } 
        }) 
        .show(); 
     } else { 
      Log.i(TAG, "Requesting permission"); 
      // Request permission. It's possible this can be auto answered if device policy 
      // sets the permission in a given state or the user denied the permission 
      // previously and checked "Never ask again". 
      ActivityCompat.requestPermissions(MainActivity.this, 
        new String[]{Manifest.permission.ACCESS_FINE_LOCATION}, 
        REQUEST_PERMISSIONS_REQUEST_CODE); 
     } 
    } 

    // If permissions are not given, we need to request permissions 
    private void requestPermissionsBody() { 
     Log.d(TAG,"getting permissions"); 
     boolean shouldProvideRationale = 
       ActivityCompat.shouldShowRequestPermissionRationale(this, 
         Manifest.permission.BODY_SENSORS); 
     Log.d(TAG,String.valueOf(Manifest.permission.BODY_SENSORS)); 
     // Provide an additional rationale to the user. This would happen if the user denied the 
     // request previously, but didn't check the "Don't ask again" checkbox. 
     if (shouldProvideRationale) { 
      Log.i(TAG, "Displaying permission rationale to provide additional context."); 
      Snackbar.make(
        findViewById(R.id.activity_main), 
        R.string.permission_rationale, 
        Snackbar.LENGTH_INDEFINITE) 
        .setAction(R.string.ok, new View.OnClickListener() { 
         @Override 
         public void onClick(View view) { 
          // Request permission 
          ActivityCompat.requestPermissions(MainActivity.this, 
            new String[]{Manifest.permission.BODY_SENSORS}, 
            REQUEST_PERMISSIONS_REQUEST_CODE); 
         } 
        }) 
        .show(); 
     } else { 
      Log.i(TAG, "Requesting permission"); 
      // Request permission. It's possible this can be auto answered if device policy 
      // sets the permission in a given state or the user denied the permission 
      // previously and checked "Never ask again". 
      ActivityCompat.requestPermissions(MainActivity.this, 
        new String[]{Manifest.permission.BODY_SENSORS}, 
        REQUEST_PERMISSIONS_REQUEST_CODE); 
     } 
    } 

onResume функции:

protected void onResume() { 
     super.onResume(); 
// This ensures that if the user denies the permissions then uses Settings to re-enable 
     // them, the app will start working. 
     buildFitnessClient(); 

     // now find the bluetooth devices 
     buildBLE(); 

     // Connect to the Client 
     mClient.connect(); 

     // Search for the data sources 
     findFitnessDataSources(); 

Строительство в API Клиент:

private void buildFitnessClient() { 
     if (mClient == null && checkPermissions()&& checkPermissionsBody()) { 

      mClient = new GoogleApiClient.Builder(this) 
        .addScope(new Scope(Scopes.FITNESS_BODY_READ)) 
        .addApi(Fitness.SENSORS_API) 
        .addApi(Fitness.BLE_API) 
        .addConnectionCallbacks(
          new GoogleApiClient.ConnectionCallbacks() { 
           @Override 
           public void onConnected(Bundle bundle) { 
            Log.i(TAG, "Connected!!!"); 
            // Now you can make calls to the Fitness APIs. 

           } 

           @Override 
           public void onConnectionSuspended(int i) { 
            // If your connection to the sensor gets lost at some point, 
            // you'll be able to determine the reason and react to it here. 
            if (i == GoogleApiClient.ConnectionCallbacks.CAUSE_NETWORK_LOST) { 
             Log.i(TAG, "Connection lost. Cause: Network Lost."); 
            } else if (i 
              == GoogleApiClient.ConnectionCallbacks.CAUSE_SERVICE_DISCONNECTED) { 
             Log.i(TAG, 
               "Connection lost. Reason: Service Disconnected"); 
            } 
           } 
          } 
        ) 
        .enableAutoManage(this, 0, new GoogleApiClient.OnConnectionFailedListener() { 
         @Override 
         public void onConnectionFailed(ConnectionResult result) { 
          Log.i(TAG, "Google Play services connection failed. Cause: " + 
            result.toString()); 
          Snackbar.make(
            MainActivity.this.findViewById(R.id.activity_main), 
            "Exception while connecting to Google Play services: " + 
              result.getErrorMessage(), 
            Snackbar.LENGTH_INDEFINITE).show(); 
         } 
        }) 
        .build(); 
     } 
    } 

     } 

Теперь найти источник фитнес:

private void findFitnessDataSources() { 
     // [START find_data_sources] 
     // Note: Fitness.SensorsApi.findDataSources() requires the ACCESS_FINE_LOCATION permission. 
     Fitness.SensorsApi.findDataSources(mClient, new DataSourcesRequest.Builder() 
       // At least one datatype must be specified. 
       .setDataTypes(DataType.TYPE_HEART_RATE_BPM) 
       // Can specify whether data type is raw or derived. 
       //.setDataSourceTypes(DataSource.TYPE_RAW) 
       .build()) 
       .setResultCallback(new ResultCallback<DataSourcesResult>() { 
        @Override 
        public void onResult(DataSourcesResult dataSourcesResult) { 
         Log.i(TAG, "Result: " + dataSourcesResult.getStatus().toString()); 

         for (DataSource dataSource : dataSourcesResult.getDataSources()) { 
          Log.i(TAG, "Data source found: " + dataSource.toString()); 
          Log.i(TAG, "Data Source type: " + dataSource.getDataType().getName()); 

          //Let's register a listener to receive Activity data! 
          if (dataSource.getDataType().equals(DataType.TYPE_HEART_RATE_BPM) 
            && mListener == null) { 
           Log.i(TAG, "Data source for Heart Rate found! Registering."); 
           registerFitnessDataListener(dataSource, 
             DataType.TYPE_HEART_RATE_BPM); 
          } 
         } 
        } 
       }); 

Построить BLE функцию - это, где вы найдете устройства Bluetooth:

private void buildBLE(){ 
     BleScanCallback callback = new BleScanCallback() { 
      @Override 
      public void onDeviceFound(BleDevice device) { 
       Log.d(TAG,"Found bluetooth Device"); 
       // A device that provides the requested data types is available 
       PendingResult<Status> pendingResult = 
         Fitness.BleApi.claimBleDevice(mClient, device); 
       Log.d(TAG,"Claimed bluetooth Device"); 
      } 
      @Override 
      public void onScanStopped() { 
       // The scan timed out or was interrupted 
       Log.d(TAG,"Scan was interruped"); 
      } 

     }; 


     StartBleScanRequest request = new StartBleScanRequest.Builder() 
       .setDataTypes(DataType.TYPE_HEART_RATE_BPM) 
       .setBleScanCallback(callback) 
       .build(); 

     if (mClient != null){ 
      PendingResult<Status> pendingResult = 
        Fitness.BleApi.startBleScan(mClient, request); 
      Log.d(TAG,"Find Sources"); 
      Log.d(TAG,"Pending result: "+pendingResult.toString()); 


     } else { 
      Log.d(TAG,"API client is null"); 
     } 
    } 

Наконец Регистрация слушателя:

private void registerFitnessDataListener(DataSource dataSource, DataType dataType) { 
     // [START register_data_listener] 
     Log.i(TAG,"Listener Started"); 
     mListener = new OnDataPointListener() { 
      @Override 
      public void onDataPoint(DataPoint dataPoint) { 
       for (Field field : dataPoint.getDataType().getFields()) { 
        Value val = dataPoint.getValue(field); 
        Log.i(TAG, "Detected DataPoint field: " + field.getName()); 
        Log.i(TAG, "Detected DataPoint value: " + val); 
       } 
      } 
     }; 

     Fitness.SensorsApi.add(
       mClient, 
       new SensorRequest.Builder() 
         .setDataSource(dataSource) // Optional but recommended for custom data sets. 
         .setDataType(dataType) // Can't be omitted. 
         .setSamplingRate(10, TimeUnit.SECONDS) 
         .build(), 
       mListener) 
       .setResultCallback(new ResultCallback<Status>() { 
        @Override 
        public void onResult(Status status) { 
         if (status.isSuccess()) { 
          Log.i(TAG, "Listener registered!"); 
         } else { 
          Log.i(TAG, "Listener not registered."); 
         } 
        } 
       }); 
     // [END register_data_listener] 
    } 

Наиболее этих функций берутся непосредственно из руководства по установке google здесь: https://developers.google.com/fit/

Проблема в том, что когда я использую эти функции, устройство Bluetooth обнаруживается и заявляется в повторном цикле. Таким образом, выход отладки выглядит примерно так:

Log.d(TAG,"Found bluetooth Device"); 
Log.d(TAG,"Claimed bluetooth Device"); 
Log.d(TAG,"Found bluetooth Device"); 
Log.d(TAG,"Claimed bluetooth Device"); 
Log.d(TAG,"Found bluetooth Device"); 
Log.d(TAG,"Claimed bluetooth Device"); 
Log.d(TAG,"Found bluetooth Device"); 
Log.d(TAG,"Claimed bluetooth Device"); 
Log.d(TAG,"Found bluetooth Device"); 
Log.d(TAG,"Claimed bluetooth Device"); 
Log.d(TAG,"Found bluetooth Device"); 
Log.d(TAG,"Claimed bluetooth Device"); 
Log.d(TAG,"Found bluetooth Device"); 
Log.d(TAG,"Claimed bluetooth Device"); 
Log.d(TAG,"Scan cancelled"); 

Несмотря на устройстве заявляемых много раз, есть данные, поступающие. Это даже несмотря на то, что слушатель зарегистрирован. Я знаю, потому что вижу строку отладки: Log.i (TAG, «Listener Started»);

Так что мой вопрос: есть ли что-нибудь неуместное в этом коде? Кто-нибудь использовал это раньше?

ответ

1

Для всех, кто интересуется использованием Google Fit с устройством BLE, ответ на этот вопрос заключается в том, что вы можете регистрировать только одно устройство за раз. Когда вы перезагружаете адаптер Bluetooth, вы должны повторно потребовать устройство BLE в приложении. Поэтому правильная процедура заключается в том, чтобы отменить устройство BLE, а затем вернуть его. Утверждение устройства несколько раз приводит к странным ошибкам.