platform channel added.

watch_integration
tahaalam 1 month ago
parent 183bcce003
commit 4912f686f9

@ -7,6 +7,7 @@ plugins {
id("com.google.gms.google-services") version "4.4.1" // Add the version here
id("dev.flutter.flutter-gradle-plugin")
id("com.huawei.agconnect")
id("kotlin-parcelize")
// id("com.mapbox.gradle.application")
// id("com.mapbox.gradle.plugins.ndk")
}
@ -25,7 +26,7 @@ android {
defaultConfig {
applicationId = "com.ejada.hmg"
// minSdk = 24
minSdk = 26
minSdk = 29
targetSdk = 36
compileSdk = 36
// targetSdk = flutter.targetSdkVersion
@ -167,6 +168,7 @@ dependencies {
implementation(files("libs/PenNavUI.aar"))
implementation(files("libs/Penguin.aar"))
implementation(files("libs/PenguinRenderer.aar"))
api(files("libs/samsung-health-data-api.aar"))
implementation("com.github.kittinunf.fuel:fuel:2.3.1")
implementation("com.github.kittinunf.fuel:fuel-android:2.3.1")

@ -9,6 +9,7 @@ import android.view.WindowManager
import androidx.annotation.NonNull;
import androidx.annotation.RequiresApi
import com.ejada.hmg.penguin.PenguinInPlatformBridge
import com.ejada.hmg.samsung_watch.SamsungWatch
import io.flutter.embedding.engine.FlutterEngine
import io.flutter.plugins.GeneratedPluginRegistrant
@ -23,6 +24,7 @@ class MainActivity: FlutterFragmentActivity() {
this.window.addFlags(WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED or WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON or WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD or WindowManager.LayoutParams.FLAG_ALLOW_LOCK_WHILE_SCREEN_ON)
PenguinInPlatformBridge(flutterEngine, this).create()
SamsungWatch(flutterEngine, this)
}
override fun onRequestPermissionsResult(

@ -0,0 +1,125 @@
package com.ejada.hmg.samsung_watch
import com.ejada.hmg.MainActivity
import android.os.Build
import android.util.Log
import androidx.annotation.RequiresApi
import com.ejada.hmg.penguin.PenguinView
import io.flutter.embedding.engine.FlutterEngine
import io.flutter.plugin.common.MethodCall
import com.ejada.hmg.PermissionManager.HostNotificationPermissionManager
import com.ejada.hmg.PermissionManager.HostBgLocationManager
import com.ejada.hmg.PermissionManager.HostGpsStateManager
import com.samsung.android.sdk.health.data.HealthDataService
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.DataTypes
import com.samsung.android.sdk.health.data.request.LocalTimeFilter
import com.samsung.android.sdk.health.data.request.Ordering
import io.flutter.plugin.common.MethodChannel
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.SupervisorJob
import kotlinx.coroutines.cancel
import kotlinx.coroutines.launch
import java.time.LocalDateTime
import java.time.LocalTime
class SamsungWatch(
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 = "SamsungWatch"
companion object {
private const val CHANNEL = "samsung_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" -> {
Log.d(TAG, "onMethodCall: init called")
dataStore = HealthDataService.getStore(mainActivity)
result.success("initialized")
}
"getPermission"->{
if(!this::dataStore.isInitialized)
result.error("DataStoreNotInitialized", "Please call init before requesting permissions", null)
val permSet = setOf(
Permission.of(DataTypes.HEART_RATE, AccessType.READ),
Permission.of(DataTypes.STEPS, AccessType.READ),
Permission.of(DataTypes.BLOOD_OXYGEN, AccessType.READ),
Permission.of(DataTypes.ACTIVITY_SUMMARY, AccessType.READ),
Permission.of(DataTypes.SLEEP, AccessType.READ),
// Permission.of(DataTypes.SKIN_TEMPERATURE, AccessType.READ),
// Permission.of(DataTypes.NUTRITION, AccessType.READ),
)
scope.launch {
try {
var granted = dataStore.getGrantedPermissions(permSet)
if(granted.containsAll(granted))
result.success("Permission Granted") // adapt result as needed
granted = dataStore.requestPermissions(permSet, mainActivity)
if(granted.containsAll(granted))
result.success("Permission Granted") // adapt result as needed
result.error("PermissionError", "Permission Not Granted", null) // adapt result as needed
} catch (e: Exception) {
Log.e(TAG, "create: getPermission failed", e)
result.error("PermissionError", e.message, null)
}
}
}
"getHeartRate"->{
val dateTime = LocalDateTime.now().with(LocalTime.MIDNIGHT)
val localTimeFilter = LocalTimeFilter.of(dateTime, dateTime.minusDays(365))
val readRequest = DataTypes.HEART_RATE.readDataRequestBuilder
.setLocalTimeFilter(localTimeFilter)
.setOrdering(Ordering.DESC)
.build()
scope.launch {
val heartRateList = dataStore.readData(readRequest).dataList
Log.d(TAG, "create: heart rate data count: ${heartRateList}")
}
}
"closeCoroutineScope"->{
destroy()
result.success("Coroutine Scope Cancelled")
}
else -> {
result.notImplemented()
}
}
}
}
fun destroy() {
scope.cancel()
}
}

@ -683,7 +683,7 @@ const DASHBOARD = 'Services/Patients.svc/REST/PatientDashboard';
class ApiConsts {
static const maxSmallScreen = 660;
static AppEnvironmentTypeEnum appEnvironmentType = AppEnvironmentTypeEnum.prod;
static AppEnvironmentTypeEnum appEnvironmentType = AppEnvironmentTypeEnum.uat;
// static String baseUrl = 'https://uat.hmgwebservices.com/'; // HIS API URL UAT

@ -1,6 +1,13 @@
import 'package:flutter/foundation.dart';
import 'package:health/health.dart';
import 'package:hmg_patient_app_new/core/common_models/smart_watch.dart';
import 'package:hmg_patient_app_new/core/utils/loading_utils.dart';
import 'package:hmg_patient_app_new/features/smartwatch_health_data/health_service.dart';
import 'package:hmg_patient_app_new/widgets/loader/bottomsheet_loader.dart';
import '../../core/dependencies.dart';
import '../../presentation/smartwatches/smart_watch_activity.dart' show SmartWatchActivity;
import '../../services/navigation_service.dart' show NavigationService;
class HealthProvider with ChangeNotifier {
final HealthService _healthService = HealthService();
@ -10,13 +17,14 @@ class HealthProvider with ChangeNotifier {
String selectedTimeRange = '7D';
int selectedTabIndex = 0;
String selectedWatchType = 'apple';
SmartWatchTypes? selectedWatchType ;
String selectedWatchURL = 'assets/images/png/smartwatches/apple-watch-5.jpg';
setSelectedWatchType(String type, String imageURL) {
setSelectedWatchType(SmartWatchTypes type, String imageURL) {
selectedWatchType = type;
selectedWatchURL = imageURL;
notifyListeners();
_healthService.addWatchHelper(type);
}
void onTabChanged(int index) {
@ -91,4 +99,27 @@ class HealthProvider with ChangeNotifier {
return DateTime.now().subtract(const Duration(days: 7));
}
}
void initDevice() async {
LoaderBottomSheet.showLoader();
notifyListeners();
final result = await _healthService.initDevice();
isLoading = false;
LoaderBottomSheet.hideLoader();
if (result.isError) {
error = 'Error initializing device: ${result.asError}';
} else {
getIt.get<NavigationService>().pushPage(page: SmartWatchActivity());
print('Device initialized successfully');
}
notifyListeners();
}
void getHeartRate() async{
isLoading = true;
notifyListeners();
final result = await _healthService.getHeartRate();
isLoading = false;
notifyListeners();
}
}

@ -1,9 +1,14 @@
import 'dart:async';
import 'dart:io';
import 'package:health/health.dart';
import 'package:hmg_patient_app_new/core/common_models/smart_watch.dart';
import 'package:hmg_patient_app_new/features/smartwatch_health_data/watch_connectors/create_watch_helper.dart';
import 'package:hmg_patient_app_new/features/smartwatch_health_data/watch_connectors/watch_helper.dart';
import 'package:permission_handler/permission_handler.dart';
import 'health_utils.dart';
import 'package:async/async.dart';
class HealthService {
static final HealthService _instance = HealthService._internal();
@ -14,6 +19,8 @@ class HealthService {
final Health health = Health();
WatchHelper? watchHelper;
final List<HealthDataType> _healthMetrics = [
HealthDataType.HEART_RATE,
// HealthDataType.STEPS,
@ -161,4 +168,23 @@ class HealthService {
return [];
}
}
void addWatchHelper(SmartWatchTypes watchType){
watchHelper = CreateWatchHelper.getWatchName(watchType) ;
}
Future<Result<bool>> initDevice() async {
if(watchHelper == null){
return Result.error('No watch helper found');
}
return await watchHelper!.initDevice();
}
FutureOr<void> getHeartRate() async {
if (watchHelper == null) {
print('No watch helper found');
return;
}
await watchHelper!.getHeartRate();
}
}

@ -0,0 +1,31 @@
import 'package:async/async.dart';
import 'package:flutter/services.dart';
class SamsungPlatformChannel {
final MethodChannel _channel = MethodChannel('samsung_watch');
Future<Result<bool>> initDevice() async {
try{
await _channel.invokeMethod('init');
return Result.value(true);
}catch(e){
return Result.error(e);
}
}
Future<Result<bool>> getRequestedPermission() async {
try{
await _channel.invokeMethod('getPermission');
return Result.value(true);
}catch(e){
return Result.error(e);
}
}
Future<Result<bool>> getHeartRate() async {
try{
await _channel.invokeMethod('getHeartRate');
return Result.value(true);
}catch(e){
return Result.error(e);
}
}
}

@ -0,0 +1,14 @@
import 'package:hmg_patient_app_new/core/common_models/smart_watch.dart';
import 'package:hmg_patient_app_new/features/smartwatch_health_data/watch_connectors/samsung_health.dart';
import 'package:hmg_patient_app_new/features/smartwatch_health_data/watch_connectors/watch_helper.dart';
class CreateWatchHelper {
static WatchHelper getWatchName(SmartWatchTypes watchType) {
switch(watchType){
case SmartWatchTypes.samsung:
return SamsungHealth();
default:
return SamsungHealth();
}
}
}

@ -0,0 +1,25 @@
import 'dart:async';
import 'package:async/src/result/result.dart';
import 'package:hmg_patient_app_new/features/smartwatch_health_data/platform_channel/samsung_platform_channel.dart';
import 'package:hmg_patient_app_new/features/smartwatch_health_data/watch_connectors/watch_helper.dart' show WatchHelper;
class SamsungHealth extends WatchHelper {
final SamsungPlatformChannel platformChannel = SamsungPlatformChannel();
@override
FutureOr<void> getHeartRate() async {
await platformChannel.getHeartRate();
}
@override
Future<Result<bool>> initDevice() async {
var result = await platformChannel.initDevice();
if(result.isError){
return result;
}
return await platformChannel.getRequestedPermission();
}
}

@ -0,0 +1,7 @@
import 'dart:async';
import 'package:async/async.dart';
abstract class WatchHelper {
Future<Result<bool>> initDevice();
FutureOr<void> getHeartRate();
}

@ -84,7 +84,7 @@ class SmartwatchHomePage extends StatelessWidget {
CustomButton(
text: LocaleKeys.select.tr(context: context),
onPressed: () {
context.read<HealthProvider>().setSelectedWatchType("apple", "assets/images/png/smartwatches/apple-watch-5.jpg");
context.read<HealthProvider>().setSelectedWatchType(SmartWatchTypes.apple, "assets/images/png/smartwatches/apple-watch-5.jpg");
getIt.get<NavigationService>().pushPage(page: SmartwatchInstructionsPage(
smartwatchDetails: SmartwatchDetails(SmartWatchTypes.apple,
"assets/images/png/smartwatches/apple-watch-5.jpg",
@ -117,7 +117,7 @@ class SmartwatchHomePage extends StatelessWidget {
CustomButton(
text: LocaleKeys.select.tr(context: context),
onPressed: () {
context.read<HealthProvider>().setSelectedWatchType("samsung", "assets/images/png/smartwatches/galaxy_watch_8_classic.jpeg");
context.read<HealthProvider>().setSelectedWatchType(SmartWatchTypes.samsung, "assets/images/png/smartwatches/galaxy_watch_8_classic.jpeg");
getIt.get<NavigationService>().pushPage(page: SmartwatchInstructionsPage(
smartwatchDetails: SmartwatchDetails(SmartWatchTypes.samsung,
"assets/images/png/smartwatches/galaxy_watch_8_classic.jpeg",
@ -149,7 +149,7 @@ class SmartwatchHomePage extends StatelessWidget {
CustomButton(
text: LocaleKeys.select.tr(context: context),
onPressed: () {
context.read<HealthProvider>().setSelectedWatchType("huawei", "assets/images/png/smartwatches/Huawei_Watch.png");
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",
@ -182,7 +182,7 @@ class SmartwatchHomePage extends StatelessWidget {
CustomButton(
text: LocaleKeys.select.tr(context: context),
onPressed: () {
context.read<HealthProvider>().setSelectedWatchType("whoop", "assets/images/png/smartwatches/Whoop_Watch.png");
context.read<HealthProvider>().setSelectedWatchType(SmartWatchTypes.whoop, "assets/images/png/smartwatches/Whoop_Watch.png");
getIt.get<NavigationService>().pushPage(page: SmartwatchInstructionsPage(
smartwatchDetails: SmartwatchDetails(SmartWatchTypes.whoop,
"assets/images/png/smartwatches/Whoop_Watch.png",

@ -12,8 +12,10 @@ import 'package:hmg_patient_app_new/services/navigation_service.dart';
import 'package:hmg_patient_app_new/theme/colors.dart';
import 'package:hmg_patient_app_new/widgets/appbar/collapsing_list_view.dart';
import 'package:hmg_patient_app_new/widgets/buttons/custom_button.dart';
import 'package:provider/provider.dart';
import '../../core/utils/utils.dart';
import '../../features/smartwatch_health_data/health_provider.dart' show HealthProvider;
class SmartwatchInstructionsPage extends StatelessWidget {
final SmartwatchDetails smartwatchDetails;
@ -34,7 +36,7 @@ class SmartwatchInstructionsPage extends StatelessWidget {
child: CustomButton(
text: LocaleKeys.getStarted.tr(context: context),
onPressed: () {
getIt.get<NavigationService>().pushPage(page: SmartWatchActivity());
context.read<HealthProvider>().initDevice();
},
backgroundColor: AppColors.primaryRedColor,
borderColor: AppColors.primaryRedColor,

Loading…
Cancel
Save