huawei watch addded

Main_App_Replacement
taha 2 weeks ago
parent c00fe3e10c
commit 532c894e16

@ -267,6 +267,9 @@
<meta-data
android:name="com.google.android.geo.API_KEY"
android:value="AIzaSyB6TERnxIr0yJ3qG4ULBZbu0sAD4tGqtng" />
<meta-data
android:name="com.huawei.hms.client.appid"
android:value="appid=116912301" />
<!--
Don't delete the meta-data below.
This is used by the Flutter tool to generate GeneratedPluginRegistrant.java

@ -8,6 +8,7 @@ import android.view.WindowManager
import androidx.annotation.NonNull;
import androidx.annotation.RequiresApi
import com.cloudsolutions.HMGPatientApp.watch.samsung_watch.SamsungWatch
import com.cloudsolutions.HMGPatientApp.watch.huawei.HuaweiWatch
import io.flutter.embedding.engine.FlutterEngine
import io.flutter.plugins.GeneratedPluginRegistrant
@ -24,6 +25,7 @@ class MainActivity: FlutterFragmentActivity() {
PenguinInPlatformBridge(flutterEngine, this).create()
SamsungWatch(flutterEngine, this)
HuaweiWatch(flutterEngine, this)
}
override fun onRequestPermissionsResult(

@ -0,0 +1,87 @@
package com.cloudsolutions.HMGPatientApp.watch.huawei
import android.os.Build
import android.util.Log
import androidx.annotation.RequiresApi
import com.cloudsolutions.HMGPatientApp.watch.samsung_watch.model.Vitals
import com.huawei.hms.adapter.AvailableAdapter
import com.huawei.hms.adapter.internal.AvailableCode
import com.samsung.android.sdk.health.data.HealthDataStore
import com.samsung.android.sdk.health.data.permission.AccessType
import com.samsung.android.sdk.health.data.permission.Permission
import com.samsung.android.sdk.health.data.request.DataType
import com.samsung.android.sdk.health.data.request.DataTypes
import com.samsung.android.sdk.health.data.request.LocalTimeFilter
import com.samsung.android.sdk.health.data.request.LocalTimeGroup
import com.samsung.android.sdk.health.data.request.LocalTimeGroupUnit
import com.samsung.android.sdk.health.data.request.Ordering
import io.flutter.embedding.engine.FlutterEngine
import io.flutter.plugin.common.MethodCall
import io.flutter.plugin.common.MethodChannel
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.SupervisorJob
import kotlinx.coroutines.launch
import java.time.LocalDateTime
import java.time.LocalTime
import com.huawei.hms.hihealth.HuaweiHiHealth
import com.cloudsolutions.HMGPatientApp.MainActivity
class HuaweiWatch(
private var flutterEngine: FlutterEngine,
private var mainActivity: MainActivity
) {
private lateinit var channel: MethodChannel
private lateinit var dataStore: HealthDataStore
private val scope = CoroutineScope(SupervisorJob() + Dispatchers.IO)
private val TAG = "HuaweiWatch"
private lateinit var vitals: MutableMap<String, List<Vitals>>
companion object {
private const val CHANNEL = "huawei_watch"
}
init{
create()
}
@RequiresApi(Build.VERSION_CODES.O)
fun create() {
Log.d(TAG, "create: is called")
// openTok = OpenTok(mainActivity, flutterEngine)
channel = MethodChannel(flutterEngine.dartExecutor.binaryMessenger, CHANNEL)
channel.setMethodCallHandler { call: MethodCall, result: MethodChannel.Result ->
when (call.method) {
"init" -> {
init(result)
}
else -> {
result.notImplemented()
}
}
}
}
fun init(result: MethodChannel.Result) {
Log.d(TAG, "onMethodCall: init called")
val mSettingController = HuaweiHiHealth.getSettingController(mainActivity);
val availableAdapter = AvailableAdapter(60400312)
val results= availableAdapter.isHuaweiMobileServicesAvailable(mainActivity) // context indicates a context object.
if (results != AvailableCode.SUCCESS) {
availableAdapter.startResolution(mainActivity, object : AvailableAdapter.AvailableCallBack {
override fun onComplete(result: Int) {
Log.d(TAG, "onComplete result: " + result)
}
})
}
result.success("init success")
}
}

@ -8,3 +8,10 @@ org.gradle.parallel=true
org.gradle.configureondemand=true
android.useAndroidX=true
android.enableImpeller=false
# This builtInKotlin flag was added automatically by Flutter migrator
android.builtInKotlin=false
# This newDsl flag was added automatically by Flutter migrator
android.newDsl=false
# Enabled parallel sync for Gradle 9.4+
org.gradle.tooling.parallel=true

@ -1,4 +1,5 @@
import 'package:flutter/foundation.dart';
import 'package:flutter/services.dart';
import 'package:health/health.dart';
import 'package:hmg_patient_app_new/core/common_models/data_points.dart';
import 'package:hmg_patient_app_new/core/common_models/smart_watch.dart';
@ -123,8 +124,10 @@ class HealthProvider with ChangeNotifier {
isLoading = false;
LoaderBottomSheet.hideLoader();
if (result.isError) {
print("the result is error ${(result.asError?.error as PlatformException)?.message}");
error = 'Error initializing device: ${result.asError}';
} else {
print("the result is not error");
LoaderBottomSheet.showLoader();
await getVitals();
// LoaderBottomSheet.hideLoader();

@ -1,86 +1,403 @@
import 'dart:async';
import 'dart:convert';
import 'package:async/src/result/result.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/services.dart';
import 'package:hmg_patient_app_new/features/smartwatch_health_data/model/vitals_data_model.dart';
import 'package:hmg_patient_app_new/features/smartwatch_health_data/watch_connectors/watch_helper.dart';
import 'package:http/http.dart';
import 'package:huawei_health/huawei_health.dart';
class HuaweiHealthDataConnector extends WatchHelper{
final MethodChannel _channel = MethodChannel('huawei_watch');
@override
Future<Result<bool>> initDevice() async{
try{
await _channel.invokeMethod('init');
}catch(e){
DataController? _dataController;
final Map<String, List<Vitals>> mappedData = <String, List<Vitals>>{};
DateTime get _defaultEndDate => DateTime.now();
DateTime get _defaultStartDate => _defaultEndDate.subtract(const Duration(days: 365));
@override
Future<Result<bool>> initDevice() async {
try {
await _channel.invokeMethod('init');
} catch (e) {
debugPrint('Huawei channel init failed: $e');
}
// List of scopes to ask for authorization.
// Note: These scopes should also be authorized on the Huawei Developer Console.
List<Scope> scopes = [
Scope.HEALTHKIT_STEP_READ, Scope.HEALTHKIT_OXYGEN_SATURATION_READ, // View and store height and weight data in Health Service Kit.
Scope.HEALTHKIT_HEARTRATE_READ, Scope.HEALTHKIT_SLEEP_READ,
Scope.HEALTHKIT_BODYTEMPERATURE_READ, Scope.HEALTHKIT_CALORIES_READ
final List<Scope> scopes = <Scope>[
Scope.HEALTHKIT_ACTIVITY_READ,
Scope.HEALTHKIT_ACTIVITY_WRITE,
Scope.HEALTHKIT_BLOODGLUCOSE_READ,
Scope.HEALTHKIT_BLOODGLUCOSE_WRITE,
Scope.HEALTHKIT_CALORIES_READ,
Scope.HEALTHKIT_CALORIES_WRITE,
Scope.HEALTHKIT_DISTANCE_READ,
Scope.HEALTHKIT_DISTANCE_WRITE,
Scope.HEALTHKIT_HEARTRATE_READ,
Scope.HEALTHKIT_HEARTRATE_WRITE,
Scope.HEALTHKIT_HEIGHTWEIGHT_READ,
Scope.HEALTHKIT_HEIGHTWEIGHT_WRITE,
Scope.HEALTHKIT_LOCATION_READ,
Scope.HEALTHKIT_LOCATION_WRITE,
Scope.HEALTHKIT_PULMONARY_READ,
Scope.HEALTHKIT_PULMONARY_WRITE,
Scope.HEALTHKIT_SLEEP_READ,
Scope.HEALTHKIT_SLEEP_WRITE,
Scope.HEALTHKIT_SPEED_READ,
Scope.HEALTHKIT_SPEED_WRITE,
Scope.HEALTHKIT_STEP_READ,
Scope.HEALTHKIT_STEP_WRITE,
Scope.HEALTHKIT_STRENGTH_READ,
Scope.HEALTHKIT_STRENGTH_WRITE,
Scope.HEALTHKIT_BODYFAT_READ,
Scope.HEALTHKIT_BODYFAT_WRITE,
Scope.HEALTHKIT_NUTRITION_READ,
Scope.HEALTHKIT_NUTRITION_WRITE,
Scope.HEALTHKIT_BLOODPRESSURE_READ,
Scope.HEALTHKIT_BLOODPRESSURE_WRITE,
Scope.HEALTHKIT_BODYTEMPERATURE_READ,
Scope.HEALTHKIT_BODYTEMPERATURE_WRITE,
Scope.HEALTHKIT_OXYGENSTATURATION_READ,
Scope.HEALTHKIT_OXYGENSTATURATION_WRITE,
Scope.HEALTHKIT_REPRODUCTIVE_READ,
Scope.HEALTHKIT_REPRODUCTIVE_WRITE,
Scope.HEALTHKIT_ACTIVITY_RECORD_READ,
Scope.HEALTHKIT_ACTIVITY_RECORD_WRITE,
Scope.HEALTHKIT_HEARTRATE_REALTIME,
Scope.HEALTHKIT_STEP_REALTIME,
Scope.HEALTHKIT_HEARTHEALTH_WRITE,
Scope.HEALTHKIT_HEARTHEALTH_READ,
Scope.HEALTHKIT_STRESS_WRITE,
Scope.HEALTHKIT_STRESS_READ,
Scope.HEALTHKIT_OXYGEN_SATURATION_WRITE,
Scope.HEALTHKIT_OXYGEN_SATURATION_READ,
Scope.HEALTHKIT_HISTORYDATA_OPEN_WEEK,
Scope.HEALTHKIT_HISTORYDATA_OPEN_MONTH,
Scope.HEALTHKIT_HISTORYDATA_OPEN_YEAR,
];
try {
bool? result = await SettingController.getHealthAppAuthorization();
debugPrint(
'Granted Scopes for result == is $result}',
);
await HealthAuth.signIn(scopes);
_dataController = await DataController.init();
if (_dataController == null) {
return Result.error(false);
}
return Result.value(true);
} on PlatformException catch (e) {
debugPrint('Error on Huawei authorization: $e');
return Result.error(false);
} catch (e) {
debugPrint('Error on authorization, Error:${e.toString()}');
debugPrint('Unexpected Huawei init error: $e');
return Result.error(false);
}
}
@override
Future<void> getActivity() async {
DataType dataTypeResult = await SettingController.readDataType(
DataType.DT_CONTINUOUS_STEPS_DELTA.name
);
try {
final ReadReply? data = await readDataType(
DataType.DT_CONTINUOUS_CALORIES_BURNT,
_defaultStartDate,
_defaultEndDate,
);
addDataToMap('activity', data, preferredKeys: const <String>['calories', 'calories_total']);
} catch (e) {
debugPrint('Error getting activity data: $e');
mappedData['activity'] = <Vitals>[];
}
}
@override
Future getBloodOxygen() {
throw UnimplementedError();
Future<void> getBloodOxygen() async {
try {
final ReadReply? data = await readDataType(
HealthDataTypes.DT_INSTANTANEOUS_SPO2,
_defaultStartDate,
_defaultEndDate,
);
addDataToMap(
'bloodOxygen',
data,
preferredKeys: const <String>['saturation', 'saturation_last', 'saturation_avg'],
transform: _normalizeSpo2,
);
} catch (e) {
debugPrint('Error getting blood oxygen data: $e');
mappedData['bloodOxygen'] = <Vitals>[];
}
}
@override
Future<void> getBodyTemperature() async {
try {
final ReadReply? data = await readDataType(
HealthDataTypes.DT_INSTANTANEOUS_BODY_TEMPERATURE,
_defaultStartDate,
_defaultEndDate,
);
addDataToMap('bodyTemperature', data, preferredKeys: const <String>['temperature']);
} catch (e) {
debugPrint('Error getting body temperature data: $e');
mappedData['bodyTemperature'] = <Vitals>[];
}
}
@override
Future getBodyTemperature() {
FutureOr<void> getHeartRate() async {
try {
final ReadReply? data = await readDataType(
DataType.DT_INSTANTANEOUS_HEART_RATE,
_defaultStartDate,
_defaultEndDate,
);
addDataToMap('heartRate', data, preferredKeys: const <String>['bpm']);
} catch (e) {
debugPrint('Error getting heart rate data: $e');
mappedData['heartRate'] = <Vitals>[];
}
}
throw UnimplementedError();
@override
FutureOr<void> getSleep() async {
try {
final ReadReply? data = await readDataType(
DataType.DT_CONTINUOUS_SLEEP,
_defaultStartDate,
_defaultEndDate,
);
addSleepDataToMap(data);
} catch (e) {
debugPrint('Error getting sleep data: $e');
mappedData['sleep'] = <Vitals>[];
}
}
@override
FutureOr<void> getHeartRate() {
throw UnimplementedError();
FutureOr<void> getSteps() async {
try {
final ReadReply? data = await readDataType(
DataType.DT_CONTINUOUS_STEPS_DELTA,
_defaultStartDate,
_defaultEndDate,
);
addDataToMap('steps', data, preferredKeys: const <String>['steps_delta', 'steps', 'step_rate']);
} catch (e) {
debugPrint('Error getting steps data: $e');
mappedData['steps'] = <Vitals>[];
}
}
@override
FutureOr<void> getSleep() {
throw UnimplementedError();
Future<Result<String>> retrieveData() async {
return Result.value(getMappedData());
}
@override
FutureOr<void> getSteps() {
throw UnimplementedError();
FutureOr<void> getDistance() async {
try {
final ReadReply? data = await readDataType(
DataType.DT_CONTINUOUS_DISTANCE_DELTA,
_defaultStartDate,
_defaultEndDate,
);
addDataToMap('distance', data, preferredKeys: const <String>['distance_delta', 'distance']);
} catch (e) {
debugPrint('Error getting distance data: $e');
mappedData['distance'] = <Vitals>[];
}
}
Future<ReadReply?> readDataType(
DataType dataType,
DateTime startTime,
DateTime endTime,
) async {
final DataCollector dataCollector = DataCollector(
dataType: dataType,
dataGenerateType: DataGenerateType.DATA_TYPE_RAW,
);
@override
Future retrieveData() {
throw UnimplementedError();
final ReadOptions readOptions = ReadOptions(
dataCollectors: <DataCollector>[dataCollector],
startTime: startTime,
endTime: endTime,
allowRemoteInquiry: true,
)..groupByTime(1, timeUnit: TimeUnit.HOURS);
try {
return await _dataController?.read(readOptions);
} on PlatformException catch (e) {
debugPrint('Huawei read error for ${dataType.name}: $e');
return null;
}
}
@override
FutureOr<void> getDistance() {
// TODO: implement getDistance
throw UnimplementedError();
void addDataToMap(
String key,
ReadReply? data, {
List<String> preferredKeys = const <String>[],
double Function(double value)? transform,
}) {
mappedData[key] = <Vitals>[];
if (data == null) {
return;
}
if (data.groups.isNotEmpty) {
for (final Group group in data.groups) {
for (final SampleSet sampleSet in group.sampleSets ?? <SampleSet>[]) {
for (final SamplePoint samplePoint in sampleSet.samplePoints) {
_addNumericSampleToMappedData(
key: key,
samplePoint: samplePoint,
preferredKeys: preferredKeys,
groupStartTime: group.startTime,
transform: transform,
);
}
}
}
return;
}
for (final SampleSet sampleSet in data.sampleSets) {
for (final SamplePoint samplePoint in sampleSet.samplePoints) {
_addNumericSampleToMappedData(
key: key,
samplePoint: samplePoint,
preferredKeys: preferredKeys,
transform: transform,
);
}
}
}
void addSleepDataToMap(ReadReply? data) {
mappedData['sleep'] = <Vitals>[];
if (data == null) {
return;
}
void appendSleepPoint(SamplePoint samplePoint, {DateTime? groupStart, DateTime? groupEnd}) {
final DateTime? start = samplePoint.startTime ?? groupStart;
final DateTime? end = samplePoint.endTime ?? groupEnd;
double? value;
if (start != null && end != null && end.isAfter(start)) {
value = end.difference(start).inMinutes / 60;
}
value ??= _extractNumericValue(
samplePoint,
const <String>['sleep_state', 'all_sleep_time', 'deep_sleep_time', 'light_sleep_time'],
);
if (value == null) {
return;
}
final String timestamp =
(start ?? samplePoint.samplingTime ?? DateTime.now()).toIso8601String();
mappedData['sleep']?.add(
Vitals(
value: value.toStringAsFixed(2),
timestamp: timestamp,
),
);
}
if (data.groups.isNotEmpty) {
for (final Group group in data.groups) {
for (final SampleSet sampleSet in group.sampleSets ?? <SampleSet>[]) {
for (final SamplePoint samplePoint in sampleSet.samplePoints) {
appendSleepPoint(
samplePoint,
groupStart: group.startTime,
groupEnd: group.endTime,
);
}
}
}
return;
}
for (final SampleSet sampleSet in data.sampleSets) {
for (final SamplePoint samplePoint in sampleSet.samplePoints) {
appendSleepPoint(samplePoint);
}
}
}
void _addNumericSampleToMappedData({
required String key,
required SamplePoint samplePoint,
required List<String> preferredKeys,
DateTime? groupStartTime,
double Function(double value)? transform,
}) {
final double? numericValue = _extractNumericValue(samplePoint, preferredKeys);
if (numericValue == null) {
return;
}
final double transformedValue = transform?.call(numericValue) ?? numericValue;
final String timestamp =
(samplePoint.samplingTime ?? samplePoint.startTime ?? groupStartTime ?? DateTime.now())
.toIso8601String();
mappedData[key]?.add(
Vitals(
value: transformedValue.toStringAsFixed(2),
timestamp: timestamp,
),
);
}
double? _extractNumericValue(SamplePoint samplePoint, List<String> preferredKeys) {
final Map<String, dynamic> values = <String, dynamic>{
...samplePoint.pairs,
...?samplePoint.fieldValues,
};
for (final String key in preferredKeys) {
final dynamic value = values[key];
if (value is num) {
return value.toDouble();
}
}
for (final dynamic value in values.values) {
if (value is num) {
return value.toDouble();
}
}
return null;
}
double _normalizeSpo2(double value) {
if (value <= 1) {
return value * 100;
}
return value;
}
String getMappedData() {
return jsonEncode(<String, dynamic>{
'heartRate': (mappedData['heartRate'] ?? <Vitals>[]).map((Vitals v) => v.toJson()).toList(),
'sleep': (mappedData['sleep'] ?? <Vitals>[]).map((Vitals v) => v.toJson()).toList(),
'steps': (mappedData['steps'] ?? <Vitals>[]).map((Vitals v) => v.toJson()).toList(),
'activity': (mappedData['activity'] ?? <Vitals>[]).map((Vitals v) => v.toJson()).toList(),
'bloodOxygen':
(mappedData['bloodOxygen'] ?? <Vitals>[]).map((Vitals v) => v.toJson()).toList(),
'bodyTemperature':
(mappedData['bodyTemperature'] ?? <Vitals>[]).map((Vitals v) => v.toJson()).toList(),
'distance': (mappedData['distance'] ?? <Vitals>[]).map((Vitals v) => v.toJson()).toList(),
});
}
}
}

@ -158,16 +158,16 @@ class SmartwatchHomePage extends StatelessWidget {
CustomButton(
text: LocaleKeys.selectSmartWatch.tr(context: context),
onPressed: () {
// context.read<HealthProvider>().setSelectedWatchType(SmartWatchTypes.huawei, "assets/images/png/smartwatches/Huawei_Watch.png");
// getIt.get<NavigationService>().pushPage(page: SmartwatchInstructionsPage(
// smartwatchDetails: SmartwatchDetails(SmartWatchTypes.huawei,
// "assets/images/png/smartwatches/Huawei_Watch.png",
// AppAssets.bluetooth,
// LocaleKeys.huaweihealthapplicationshouldbeinstalledinyourphone.tr(context: context),
// LocaleKeys.unabletodetectapplicationinstalledpleasecomebackonceinstalled.tr(context: context),
// LocaleKeys.huaweiwatchshouldbeconnected.tr(context: context)),
// ));
showUnavailableDialog(context);
context.read<HealthProvider>().setSelectedWatchType(SmartWatchTypes.huawei, "assets/images/png/smartwatches/Huawei_Watch.png");
getIt.get<NavigationService>().pushPage(page: SmartwatchInstructionsPage(
smartwatchDetails: SmartwatchDetails(SmartWatchTypes.huawei,
"assets/images/png/smartwatches/Huawei_Watch.png",
AppAssets.bluetooth,
LocaleKeys.huaweihealthapplicationshouldbeinstalledinyourphone.tr(context: context),
LocaleKeys.unabletodetectapplicationinstalledpleasecomebackonceinstalled.tr(context: context),
LocaleKeys.huaweiwatchshouldbeconnected.tr(context: context)),
));
// showUnavailableDialog(context);
},
backgroundColor: AppColors.primaryRedColor.withAlpha(40),
borderColor: AppColors.primaryRedColor.withAlpha(0),

Loading…
Cancel
Save