Android: Как получить данные Google Fit с Wearable устройства?
Я выполняю те же шаги, описанные здесь здесь (часть подключения клиента Google Fit работает нормально).
final DataType dataType=TYPE_STEP_COUNT_DELTA;
DataSourcesRequest requestData = new DataSourcesRequest.Builder()
.setDataTypes(dataType) // At least one datatype must be specified.
.build();
Fitness.SensorsApi.findDataSources(mClient, requestData)
.setResultCallback(new ResultCallback<DataSourcesResult>() {
@Override
public void onResult(DataSourcesResult dataSourcesResult) {
Log.i(TAG, "Result: " + dataSourcesResult.getDataSources().size() + " sources "
+ 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());
}
}
});
Когда я запрашиваю источники данных, я получаю только один результат, который является смартфоном. Если я добавлю слушателя, я действительно получаю данные, чтобы он работал.
Однако он также подключен к Android Wear smartwatch Gear Live с Android Wear на телефоне. Google Fit установлен в обоих из них, но я хотел бы получить данные из smartwatch.
В официальном руководстве я прочитал
API датчиков предоставляет доступ к необработанным потокам данных датчика из датчики, доступные на устройстве Android, и от датчиков, доступных в сопутствующих устройств, таких как носимые.
Этот код работает на смартфоне, поэтому я думаю, что было бы правильным ожидать источники данных из сопутствующего smartwatch. Но это похоже на невидимое для моего телефона приложение. Я делаю что-то неправильно?
EDIT:
public class MainActivity extends AppCompatActivity {
private final static String TAG = "main_mobile";
private static final int REQUEST_OAUTH = 1;
private final static String DATE_FORMAT = "yyyy.MM.dd HH:mm:ss";
private static final String AUTH_PENDING = "auth_state_pending";
private boolean authInProgress = false;
private GoogleApiClient mClient = null;
private final static DataType dataType = TYPE_STEP_COUNT_DELTA;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
if (savedInstanceState != null) {
authInProgress = savedInstanceState.getBoolean(AUTH_PENDING);
}
mClient = new GoogleApiClient.Builder(this)
.addApi(Fitness.SENSORS_API)
.addApi(Fitness.RECORDING_API)
.addApi(Fitness.HISTORY_API)
.addScope(new Scope(Scopes.FITNESS_ACTIVITY_READ_WRITE))
.addConnectionCallbacks(connectionCallbacks)
.addOnConnectionFailedListener(connectionFailCallbacks)
.build();
}
private void initFitness() {
DataSourcesRequest requestData = new DataSourcesRequest.Builder()
.setDataTypes(dataType)
.build();
Fitness.SensorsApi.findDataSources(mClient, requestData)
.setResultCallback(new ResultCallback<DataSourcesResult>() {
@Override
public void onResult(DataSourcesResult dataSourcesResult) {
Log.i(TAG, "Result: " + dataSourcesResult.getDataSources().size() + " sources " + dataSourcesResult.getStatus().toString());
for (DataSource dataSource : dataSourcesResult.getDataSources()) {
Log.i(TAG, "\nData source found: \n\t" + dataSource.toString() + "\n\tType: " + dataSource.getDataType().getName());
}
}
});
}
@Override
protected void onStart() {
super.onStart();
Log.i(TAG, "Connecting...");
mClient.connect();
}
@Override
protected void onStop() {
super.onStop();
if (mClient.isConnected()) {
mClient.disconnect();
}
}
@Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
outState.putBoolean(AUTH_PENDING, authInProgress);
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if (requestCode == REQUEST_OAUTH) {
authInProgress = false;
if (resultCode == RESULT_OK) {
// Make sure the app is not already connected or attempting to connect
if (!mClient.isConnecting() && !mClient.isConnected()) {
mClient.connect();
}
}
}
}
GoogleApiClient.ConnectionCallbacks connectionCallbacks = new GoogleApiClient.ConnectionCallbacks() {
@Override
public void onConnected(Bundle bundle) {
Log.i(TAG, "Connected!!!");
// Now you can make calls to the Fitness APIs.
// Put application specific code here.
initFitness();
}
@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");
}
}
};
GoogleApiClient.OnConnectionFailedListener connectionFailCallbacks = new GoogleApiClient.OnConnectionFailedListener() {
// Called whenever the API client fails to connect.
@Override
public void onConnectionFailed(ConnectionResult result) {
Log.i(TAG, "Connection failed. Cause: " + result.toString());
if (!result.hasResolution()) {
// Show the localized error dialog
GooglePlayServicesUtil.getErrorDialog(result.getErrorCode(), MainActivity.this, 0).show();
return;
}
// The failure has a resolution. Resolve it.
// Called typically when the app is not yet authorized, and an
// authorization dialog is displayed to the user.
if (!authInProgress) {
try {
Log.i(TAG, "Attempting to resolve failed connection");
authInProgress = true;
result.startResolutionForResult(MainActivity.this, REQUEST_OAUTH);
} catch (IntentSender.SendIntentException e) {
Log.e(TAG, "Exception while starting resolution activity", e);
}
}
}
};
}
Ответы
Ответ 1
Я не пробовал ничего из этого.
Кажется, что Samsung Gear Live Sensors не поддерживается из коробки, но вы можете заставить его работать через программные датчики:
Ваша передача в реальном времени
Как сказано в этом SO-ответе,
Часы Samsung Gear Live не рекламируют себя как BLE heart скорость мониторинга и, следовательно, не делает данные о сердечном ритме доступный через обычный Bluetooth Low Energy API или Google Fit API, который построен на нем.
Поддерживаемые датчики
Как сказано в официальных документах,
Google Fit включает поддержку датчиков на мобильном устройстве и Датчики низкой мощности Bluetooth в сочетании с устройством. Google Fit позволяет разработчики реализуют поддержку других датчиков и раскрывают их как программные датчики в приложениях для Android. Датчики, поддерживаемые Google Fit, являются доступный для приложений Android в качестве объектов источника данных.
Возможное решение
Кажется возможным реализовать дополнительные программные датчики.
(Скопированный шаблон для этого находится в нижней части сообщения, потому что он длинный).
Полученные данные будут доступны после get-heart-rate-from-sensor-samsung-gear-live.
Добавьте это в файл манифеста:
<service android:name="com.example.MySensorService"
android:process=":sensor">
<intent-filter>
<action android:name="com.google.android.gms.fitness.service.FitnessSensorService"/>
<!-- include at least one mimeType filter for the supported data types -->
<data android:mimeType="vnd.google.fitness.data_type/com.google.heart_rate.bpm"/>
</intent-filter>
</service>
и плоть это Service
вне:
import com.google.android.gms.common.*;
import com.google.android.gms.common.api.*;
import com.google.android.gms.fitness.*;
import com.google.android.gms.fitness.data.*;
import com.google.android.gms.fitness.service.*;
...
public class MySensorService extends FitnessSensorService {
@Override
public void onCreate() {
super.onCreate();
// 1. Initialize your software sensor(s).
// 2. Create DataSource representations of your software sensor(s).
// 3. Initialize some data structure to keep track of a registration for each sensor.
}
@Override
protected List<DataSource> onFindDataSources(List<DataType> dataTypes) {
// 1. Find which of your software sensors provide the data types requested.
// 2. Return those as a list of DataSource objects.
}
@Override
protected boolean onRegister(FitnessSensorServiceRequest request) {
// 1. Determine which sensor to register with request.getDataSource().
// 2. If a registration for this sensor already exists, replace it with this one.
// 3. Keep (or update) a reference to the request object.
// 4. Configure your sensor according to the request parameters.
// 5. When the sensor has new data, deliver it to the platform by calling
// request.getDispatcher().publish(List<DataPoint> dataPoints)
}
@Override
protected boolean onUnregister(DataSource dataSource) {
// 1. Configure this sensor to stop delivering data to the platform
// 2. Discard the reference to the registration request object
}
}