mirror of
https://codeberg.org/Freeyourgadget/Gadgetbridge.git
synced 2025-01-25 08:05:55 +01:00
Garmin: App management (WIP)
This commit is contained in:
parent
b453d8ef4c
commit
a1fa2b11a6
@ -92,20 +92,20 @@ public class AppManagerActivity extends AbstractGBFragmentActivity {
|
|||||||
enabledTabsList.add("watchfaces");
|
enabledTabsList.add("watchfaces");
|
||||||
}
|
}
|
||||||
|
|
||||||
FloatingActionButton fab = (FloatingActionButton) findViewById(R.id.fab);
|
FloatingActionButton fab = findViewById(R.id.fab);
|
||||||
assert fab != null;
|
if (coordinator.supportsFlashing()) {
|
||||||
fab.setOnClickListener(new View.OnClickListener() {
|
fab.setOnClickListener(v -> {
|
||||||
@Override
|
|
||||||
public void onClick(View v) {
|
|
||||||
Intent intent = new Intent(Intent.ACTION_OPEN_DOCUMENT);
|
Intent intent = new Intent(Intent.ACTION_OPEN_DOCUMENT);
|
||||||
intent.addCategory(Intent.CATEGORY_OPENABLE);
|
intent.addCategory(Intent.CATEGORY_OPENABLE);
|
||||||
intent.setType("*/*");
|
intent.setType("*/*");
|
||||||
startActivityForResult(intent, READ_REQUEST_CODE);
|
startActivityForResult(intent, READ_REQUEST_CODE);
|
||||||
}
|
});
|
||||||
});
|
} else {
|
||||||
|
fab.setVisibility(View.GONE);
|
||||||
|
}
|
||||||
|
|
||||||
// Set up the ViewPager with the sections adapter.
|
// Set up the ViewPager with the sections adapter.
|
||||||
ViewPager viewPager = (ViewPager) findViewById(R.id.appmanager_pager);
|
ViewPager viewPager = findViewById(R.id.appmanager_pager);
|
||||||
if (viewPager != null) {
|
if (viewPager != null) {
|
||||||
viewPager.setAdapter(getPagerAdapter());
|
viewPager.setAdapter(getPagerAdapter());
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,7 @@
|
|||||||
package nodomain.freeyourgadget.gadgetbridge.devices.garmin;
|
package nodomain.freeyourgadget.gadgetbridge.devices.garmin;
|
||||||
|
|
||||||
|
import android.app.Activity;
|
||||||
|
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@ -7,6 +9,7 @@ import java.util.List;
|
|||||||
import nodomain.freeyourgadget.gadgetbridge.GBApplication;
|
import nodomain.freeyourgadget.gadgetbridge.GBApplication;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.GBException;
|
import nodomain.freeyourgadget.gadgetbridge.GBException;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.R;
|
import nodomain.freeyourgadget.gadgetbridge.R;
|
||||||
|
import nodomain.freeyourgadget.gadgetbridge.activities.appmanager.AppManagerActivity;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.activities.devicesettings.DeviceSpecificSettings;
|
import nodomain.freeyourgadget.gadgetbridge.activities.devicesettings.DeviceSpecificSettings;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.activities.devicesettings.DeviceSpecificSettingsCustomizer;
|
import nodomain.freeyourgadget.gadgetbridge.activities.devicesettings.DeviceSpecificSettingsCustomizer;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.activities.devicesettings.DeviceSpecificSettingsScreen;
|
import nodomain.freeyourgadget.gadgetbridge.activities.devicesettings.DeviceSpecificSettingsScreen;
|
||||||
@ -218,6 +221,26 @@ public abstract class GarminCoordinator extends AbstractBLEDeviceCoordinator {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean supportsAppsManagement(final GBDevice device) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean supportsCachedAppManagement(GBDevice device) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Class<? extends Activity> getAppsManagementActivity() {
|
||||||
|
return AppManagerActivity.class;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean supportsAppListFetching() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
public boolean supportsAgpsUpdates(final GBDevice device) {
|
public boolean supportsAgpsUpdates(final GBDevice device) {
|
||||||
return !getPrefs(device).getString(GarminPreferences.PREF_AGPS_KNOWN_URLS, "").isEmpty();
|
return !getPrefs(device).getString(GarminPreferences.PREF_AGPS_KNOWN_URLS, "").isEmpty();
|
||||||
}
|
}
|
||||||
|
@ -51,6 +51,7 @@ import nodomain.freeyourgadget.gadgetbridge.model.WeatherSpec;
|
|||||||
import nodomain.freeyourgadget.gadgetbridge.proto.garmin.GdiCore;
|
import nodomain.freeyourgadget.gadgetbridge.proto.garmin.GdiCore;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.proto.garmin.GdiDeviceStatus;
|
import nodomain.freeyourgadget.gadgetbridge.proto.garmin.GdiDeviceStatus;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.proto.garmin.GdiFindMyWatch;
|
import nodomain.freeyourgadget.gadgetbridge.proto.garmin.GdiFindMyWatch;
|
||||||
|
import nodomain.freeyourgadget.gadgetbridge.proto.garmin.GdiInstalledAppsService;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.proto.garmin.GdiSettingsService;
|
import nodomain.freeyourgadget.gadgetbridge.proto.garmin.GdiSettingsService;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.proto.garmin.GdiSmartProto;
|
import nodomain.freeyourgadget.gadgetbridge.proto.garmin.GdiSmartProto;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.service.btle.AbstractBTLEDeviceSupport;
|
import nodomain.freeyourgadget.gadgetbridge.service.btle.AbstractBTLEDeviceSupport;
|
||||||
@ -314,6 +315,30 @@ public class GarminSupport extends AbstractBTLEDeviceSupport implements ICommuni
|
|||||||
sendOutgoingMessage("delete notification " + id, notificationsHandler.onDeleteNotification(id));
|
sendOutgoingMessage("delete notification " + id, notificationsHandler.onDeleteNotification(id));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onAppInfoReq() {
|
||||||
|
sendOutgoingMessage(
|
||||||
|
"request apps",
|
||||||
|
protocolBufferHandler.prepareProtobufRequest(
|
||||||
|
GdiSmartProto.Smart.newBuilder().setInstalledAppsService(
|
||||||
|
GdiInstalledAppsService.InstalledAppsService.newBuilder().setGetInstalledAppsRequest(
|
||||||
|
GdiInstalledAppsService.InstalledAppsService.GetInstalledAppsRequest.newBuilder()
|
||||||
|
.setAppType(GdiInstalledAppsService.InstalledAppsService.AppType.ALL)
|
||||||
|
)
|
||||||
|
).build()
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onAppStart(final UUID uuid, final boolean start) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onAppDelete(final UUID uuid) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onSendWeather(final ArrayList<WeatherSpec> weatherSpecs) { //todo: find the closest one relative to the requested lat/long
|
public void onSendWeather(final ArrayList<WeatherSpec> weatherSpecs) { //todo: find the closest one relative to the requested lat/long
|
||||||
|
@ -14,13 +14,16 @@ import java.util.HashMap;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
import nodomain.freeyourgadget.gadgetbridge.activities.devicesettings.DeviceSettingsPreferenceConst;
|
import nodomain.freeyourgadget.gadgetbridge.activities.devicesettings.DeviceSettingsPreferenceConst;
|
||||||
|
import nodomain.freeyourgadget.gadgetbridge.deviceevents.GBDeviceEventAppInfo;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.deviceevents.GBDeviceEventBatteryInfo;
|
import nodomain.freeyourgadget.gadgetbridge.deviceevents.GBDeviceEventBatteryInfo;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.deviceevents.GBDeviceEventUpdatePreferences;
|
import nodomain.freeyourgadget.gadgetbridge.deviceevents.GBDeviceEventUpdatePreferences;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.devices.garmin.GarminPreferences;
|
import nodomain.freeyourgadget.gadgetbridge.devices.garmin.GarminPreferences;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.externalevents.gps.GBLocationProviderType;
|
import nodomain.freeyourgadget.gadgetbridge.externalevents.gps.GBLocationProviderType;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.externalevents.gps.GBLocationService;
|
import nodomain.freeyourgadget.gadgetbridge.externalevents.gps.GBLocationService;
|
||||||
|
import nodomain.freeyourgadget.gadgetbridge.impl.GBDeviceApp;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.model.CannedMessagesSpec;
|
import nodomain.freeyourgadget.gadgetbridge.model.CannedMessagesSpec;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.proto.garmin.GdiCalendarService;
|
import nodomain.freeyourgadget.gadgetbridge.proto.garmin.GdiCalendarService;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.proto.garmin.GdiCore;
|
import nodomain.freeyourgadget.gadgetbridge.proto.garmin.GdiCore;
|
||||||
@ -28,6 +31,7 @@ import nodomain.freeyourgadget.gadgetbridge.proto.garmin.GdiDataTransferService;
|
|||||||
import nodomain.freeyourgadget.gadgetbridge.proto.garmin.GdiDeviceStatus;
|
import nodomain.freeyourgadget.gadgetbridge.proto.garmin.GdiDeviceStatus;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.proto.garmin.GdiFindMyWatch;
|
import nodomain.freeyourgadget.gadgetbridge.proto.garmin.GdiFindMyWatch;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.proto.garmin.GdiHttpService;
|
import nodomain.freeyourgadget.gadgetbridge.proto.garmin.GdiHttpService;
|
||||||
|
import nodomain.freeyourgadget.gadgetbridge.proto.garmin.GdiInstalledAppsService;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.proto.garmin.GdiSmartProto;
|
import nodomain.freeyourgadget.gadgetbridge.proto.garmin.GdiSmartProto;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.proto.garmin.GdiSmsNotification;
|
import nodomain.freeyourgadget.gadgetbridge.proto.garmin.GdiSmsNotification;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.garmin.http.DataTransferHandler;
|
import nodomain.freeyourgadget.gadgetbridge.service.devices.garmin.http.DataTransferHandler;
|
||||||
@ -119,6 +123,47 @@ public class ProtocolBufferHandler implements MessageHandler {
|
|||||||
processed = true;
|
processed = true;
|
||||||
processProtobufFindMyWatchResponse(smart.getFindMyWatchService());
|
processProtobufFindMyWatchResponse(smart.getFindMyWatchService());
|
||||||
}
|
}
|
||||||
|
if (smart.hasInstalledAppsService()) {
|
||||||
|
processed = true;
|
||||||
|
final List<GBDeviceApp> apps = new ArrayList<>();
|
||||||
|
|
||||||
|
if (smart.getInstalledAppsService().hasGetInstalledAppsResponse()) {
|
||||||
|
final GdiInstalledAppsService.InstalledAppsService.GetInstalledAppsResponse installedAppsResponse = smart.getInstalledAppsService().getGetInstalledAppsResponse();
|
||||||
|
for (final GdiInstalledAppsService.InstalledAppsService.InstalledApp installedApp : installedAppsResponse.getInstalledAppsList()) {
|
||||||
|
GBDeviceApp.Type type = GBDeviceApp.Type.UNKNOWN;
|
||||||
|
|
||||||
|
switch (installedApp.getType()) {
|
||||||
|
case WATCH_APP:
|
||||||
|
type = GBDeviceApp.Type.APP_SYSTEM;
|
||||||
|
continue;
|
||||||
|
case WIDGET:
|
||||||
|
type = GBDeviceApp.Type.APP_GENERIC;
|
||||||
|
break;
|
||||||
|
case WATCH_FACE:
|
||||||
|
type = GBDeviceApp.Type.WATCHFACE;
|
||||||
|
break;
|
||||||
|
case DATA_FIELD:
|
||||||
|
type = GBDeviceApp.Type.APP_ACTIVITYTRACKER;
|
||||||
|
break;
|
||||||
|
case ACTIVITY:
|
||||||
|
type = GBDeviceApp.Type.APP_ACTIVITYTRACKER;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
apps.add(new GBDeviceApp(
|
||||||
|
UUID.nameUUIDFromBytes(installedApp.getStoreAppId().toByteArray()),
|
||||||
|
installedApp.getName(),
|
||||||
|
"",
|
||||||
|
String.valueOf(installedApp.getVersion()),
|
||||||
|
type
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
final GBDeviceEventAppInfo appInfoCmd = new GBDeviceEventAppInfo();
|
||||||
|
appInfoCmd.apps = apps.toArray(new GBDeviceApp[0]);
|
||||||
|
deviceSupport.evaluateGBDeviceEvent(appInfoCmd);
|
||||||
|
}
|
||||||
|
}
|
||||||
if (!processed) {
|
if (!processed) {
|
||||||
LOG.warn("Unknown protobuf request: {}", smart);
|
LOG.warn("Unknown protobuf request: {}", smart);
|
||||||
message.setStatusMessage(new ProtobufStatusMessage(message.getMessageType(), GFDIMessage.Status.ACK, message.getRequestId(), message.getDataOffset(), ProtobufStatusMessage.ProtobufChunkStatus.DISCARDED, ProtobufStatusMessage.ProtobufStatusCode.UNKNOWN_REQUEST_ID));
|
message.setStatusMessage(new ProtobufStatusMessage(message.getMessageType(), GFDIMessage.Status.ACK, message.getRequestId(), message.getDataOffset(), ProtobufStatusMessage.ProtobufChunkStatus.DISCARDED, ProtobufStatusMessage.ProtobufStatusCode.UNKNOWN_REQUEST_ID));
|
||||||
|
@ -0,0 +1,15 @@
|
|||||||
|
package nodomain.freeyourgadget.gadgetbridge.service.devices.garmin.apps;
|
||||||
|
|
||||||
|
import nodomain.freeyourgadget.gadgetbridge.service.devices.garmin.GarminSupport;
|
||||||
|
|
||||||
|
public class GarminAppsService {
|
||||||
|
private final GarminSupport deviceSupport;
|
||||||
|
|
||||||
|
public GarminAppsService(final GarminSupport deviceSupport) {
|
||||||
|
this.deviceSupport = deviceSupport;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void requestAppList() {
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
61
app/src/main/proto/garmin/gdi_installed_apps_service.proto
Normal file
61
app/src/main/proto/garmin/gdi_installed_apps_service.proto
Normal file
@ -0,0 +1,61 @@
|
|||||||
|
syntax = "proto2";
|
||||||
|
|
||||||
|
package garmin_vivomovehr;
|
||||||
|
|
||||||
|
option java_package = "nodomain.freeyourgadget.gadgetbridge.proto.garmin";
|
||||||
|
|
||||||
|
message InstalledAppsService {
|
||||||
|
enum AppType {
|
||||||
|
UNKNOWN_APP_TYPE = 0;
|
||||||
|
WATCH_APP = 1;
|
||||||
|
WIDGET = 2;
|
||||||
|
WATCH_FACE = 3;
|
||||||
|
DATA_FIELD = 4;
|
||||||
|
ALL = 5;
|
||||||
|
NONE = 6;
|
||||||
|
AUDIO_CONTENT_PROVIDER = 7;
|
||||||
|
ACTIVITY = 8;
|
||||||
|
}
|
||||||
|
|
||||||
|
message InstalledApp {
|
||||||
|
required bytes storeAppId = 1;
|
||||||
|
required AppType type = 2;
|
||||||
|
required string name = 3;
|
||||||
|
required bool disabled = 4;
|
||||||
|
optional uint32 version = 5;
|
||||||
|
optional string fileName = 6;
|
||||||
|
optional uint64 fileSize = 7;
|
||||||
|
optional uint32 nativeAppId = 8;
|
||||||
|
optional bool favorite = 9;
|
||||||
|
}
|
||||||
|
|
||||||
|
optional GetInstalledAppsRequest getInstalledAppsRequest = 1;
|
||||||
|
optional GetInstalledAppsResponse getInstalledAppsResponse = 2;
|
||||||
|
optional DeleteAppRequest deleteAppRequest = 3;
|
||||||
|
optional DeleteAppResponse deleteAppResponse = 4;
|
||||||
|
|
||||||
|
message GetInstalledAppsRequest {
|
||||||
|
required AppType appType = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
message GetInstalledAppsResponse {
|
||||||
|
required uint64 availableSpace = 1;
|
||||||
|
required uint64 availableSlots = 2;
|
||||||
|
repeated InstalledApp installedApps = 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
message DeleteAppRequest {
|
||||||
|
required bytes storeAppId = 1;
|
||||||
|
required AppType appType = 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
message DeleteAppResponse {
|
||||||
|
enum Status {
|
||||||
|
UNKNOWN_STATUS = 0;
|
||||||
|
OK = 1;
|
||||||
|
FAILED_TO_DELETE = 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
required Status status = 1;
|
||||||
|
}
|
||||||
|
}
|
@ -8,6 +8,7 @@ import "garmin/gdi_device_status.proto";
|
|||||||
import "garmin/gdi_find_my_watch.proto";
|
import "garmin/gdi_find_my_watch.proto";
|
||||||
import "garmin/gdi_core.proto";
|
import "garmin/gdi_core.proto";
|
||||||
import "garmin/gdi_http_service.proto";
|
import "garmin/gdi_http_service.proto";
|
||||||
|
import "garmin/gdi_installed_apps_service.proto";
|
||||||
import "garmin/gdi_data_transfer_service.proto";
|
import "garmin/gdi_data_transfer_service.proto";
|
||||||
import "garmin/gdi_sms_notification.proto";
|
import "garmin/gdi_sms_notification.proto";
|
||||||
import "garmin/gdi_calendar_service.proto";
|
import "garmin/gdi_calendar_service.proto";
|
||||||
@ -16,6 +17,7 @@ import "garmin/gdi_settings_service.proto";
|
|||||||
message Smart {
|
message Smart {
|
||||||
optional CalendarService calendar_service = 1;
|
optional CalendarService calendar_service = 1;
|
||||||
optional HttpService http_service = 2;
|
optional HttpService http_service = 2;
|
||||||
|
optional InstalledAppsService installed_apps_service = 3;
|
||||||
optional DataTransferService data_transfer_service = 7;
|
optional DataTransferService data_transfer_service = 7;
|
||||||
optional DeviceStatusService device_status_service = 8;
|
optional DeviceStatusService device_status_service = 8;
|
||||||
optional FindMyWatchService find_my_watch_service = 12;
|
optional FindMyWatchService find_my_watch_service = 12;
|
||||||
@ -23,39 +25,3 @@ message Smart {
|
|||||||
optional SmsNotificationService sms_notification_service = 16;
|
optional SmsNotificationService sms_notification_service = 16;
|
||||||
optional SettingsService settings_service = 42;
|
optional SettingsService settings_service = 42;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
1: CALENDAR_EVENTS_SERVICE_FIELD_NUMBER
|
|
||||||
2: CONNECT_IQ_HTTP_SERVICE_FIELD_NUMBER
|
|
||||||
3: CONNECT_IQ_INSTALLED_APPS_SERVICE_FIELD_NUMBER
|
|
||||||
4: CONNECT_IQ_APP_SETTINGS_SERVICE_FIELD_NUMBER
|
|
||||||
5: INTERNATIONAL_GOLF_SERVICE_FIELD_NUMBER
|
|
||||||
6: SWING_SENSOR_SERVICE_FIELD_NUMBER
|
|
||||||
7: DATA_TRANSFER_SERVICE_FIELD_NUMBER
|
|
||||||
8: DEVICE_STATUS_SERVICE_FIELD_NUMBER
|
|
||||||
9: INCIDENT_DETECTION_SERVICE_FIELD_NUMBER
|
|
||||||
10: AUDIO_PROMPTS_SERVICE_FIELD_NUMBER
|
|
||||||
11: WIFI_SETUP_SERVICE_FIELD_NUMBER
|
|
||||||
12: FIND_MY_WATCH_SERVICE_FIELD_NUMBER
|
|
||||||
13: CORE_SERVICE_FIELD_NUMBER
|
|
||||||
14: GROUP_LIVE_TRACK_SERVICE_FIELD_NUMBER
|
|
||||||
15: EXPRESSPAY_COMMAND_SERVICE_FIELD_NUMBER
|
|
||||||
16: SMS_NOTIFICATION_SERVICE_FIELD_NUMBER
|
|
||||||
17: LIVE_TRACK_MESSAGING_SERVICE_FIELD_NUMBER
|
|
||||||
18: INSTANT_INPUT_SERVICE_FIELD_NUMBER
|
|
||||||
19: SPORT_PROFILE_SETUP_SERVICE_FIELD_NUMBER
|
|
||||||
20: HSA_DATA_SERVICE_FIELD_NUMBER
|
|
||||||
21: LIVE_TRACK_SERVICE_FIELD_NUMBER
|
|
||||||
22: EXPLORE_SYNC_SERVICE_FIELD_NUMBER
|
|
||||||
23: WAY_POINT_TRANSFER_SERVICE_FIELD_NUMBER
|
|
||||||
24: DEVICE_MESSAGE_SERVICE_FIELD_NUMBER
|
|
||||||
25: LTE_SERVICE_FIELD_NUMBER
|
|
||||||
26: ANTI_THEFT_ALARM_SERVICE_FIELD_NUMBER
|
|
||||||
27: CREDENTIALS_SERVICE_FIELD_NUMBER
|
|
||||||
28: INREACH_TRACKING_SERVICE_FIELD_NUMBER
|
|
||||||
29: INREACH_MESSAGING_SERVICE_FIELD_NUMBER
|
|
||||||
30: EVENT_SHARING_FIELD_NUMBER
|
|
||||||
31: GENERIC_ITEM_TRANSFER_SERVICE_FIELD_NUMBER
|
|
||||||
32: INREACH_CONTACT_SYNC_SERVICE_FIELD_NUMBER
|
|
||||||
33: HAND_CALIBRATION_SERVICE_FIELD_NUMBER
|
|
||||||
*/
|
|
||||||
|
Loading…
Reference in New Issue
Block a user