package issue resolution
parent
358207a539
commit
342afe290b
@ -0,0 +1,27 @@
|
|||||||
|
//package com.cloud.diplomaticquarterapp
|
||||||
|
package com.ejada.hmg
|
||||||
|
|
||||||
|
|
||||||
|
import io.flutter.app.FlutterApplication
|
||||||
|
|
||||||
|
class Application : FlutterApplication() {
|
||||||
|
override fun onCreate() {
|
||||||
|
super.onCreate()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//import io.flutter.app.FlutterApplication
|
||||||
|
//import io.flutter.plugin.common.PluginRegistry
|
||||||
|
//import io.flutter.plugin.common.PluginRegistry.PluginRegistrantCallback
|
||||||
|
//import io.flutter.plugins.firebasemessaging.FlutterFirebaseMessagingService
|
||||||
|
//
|
||||||
|
//class Application : FlutterApplication(), PluginRegistrantCallback {
|
||||||
|
// override fun onCreate() {
|
||||||
|
// super.onCreate()
|
||||||
|
// FlutterFirebaseMessagingService.setPluginRegistrant(this)
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// override fun registerWith(registry: PluginRegistry?) {
|
||||||
|
// FirebaseCloudMessagingPluginRegistrant.registerWith(registry)
|
||||||
|
// }
|
||||||
|
//}
|
||||||
@ -0,0 +1,80 @@
|
|||||||
|
package com.ejada.hmg
|
||||||
|
|
||||||
|
import android.content.Intent
|
||||||
|
import android.content.pm.PackageManager
|
||||||
|
import android.os.Build
|
||||||
|
import android.util.Log
|
||||||
|
import android.view.WindowManager
|
||||||
|
import androidx.annotation.NonNull;
|
||||||
|
import androidx.annotation.RequiresApi
|
||||||
|
import com.ejada.hmg.watch.samsung_watch.SamsungWatch
|
||||||
|
import com.ejada.hmg.watch.huawei.HuaweiWatch
|
||||||
|
import io.flutter.embedding.engine.FlutterEngine
|
||||||
|
import io.flutter.plugins.GeneratedPluginRegistrant
|
||||||
|
|
||||||
|
import io.flutter.embedding.android.FlutterFragmentActivity
|
||||||
|
|
||||||
|
|
||||||
|
class MainActivity: FlutterFragmentActivity() {
|
||||||
|
|
||||||
|
@RequiresApi(Build.VERSION_CODES.O)
|
||||||
|
override fun configureFlutterEngine(@NonNull flutterEngine: FlutterEngine) {
|
||||||
|
GeneratedPluginRegistrant.registerWith(flutterEngine);
|
||||||
|
// Create Flutter Platform Bridge
|
||||||
|
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)
|
||||||
|
HuaweiWatch(flutterEngine, this)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onRequestPermissionsResult(
|
||||||
|
requestCode: Int,
|
||||||
|
permissions: Array<out String>,
|
||||||
|
grantResults: IntArray
|
||||||
|
) {
|
||||||
|
super.onRequestPermissionsResult(requestCode, permissions, grantResults)
|
||||||
|
|
||||||
|
val granted = grantResults.all { it == PackageManager.PERMISSION_GRANTED }
|
||||||
|
val intent = Intent("PERMISSION_RESULT_ACTION").apply {
|
||||||
|
putExtra("PERMISSION_GRANTED", granted)
|
||||||
|
}
|
||||||
|
sendBroadcast(intent)
|
||||||
|
|
||||||
|
// Log the request code and permission results
|
||||||
|
Log.d("PermissionsResult", "Request Code: $requestCode")
|
||||||
|
Log.d("PermissionsResult", "Permissions: ${permissions.joinToString()}")
|
||||||
|
Log.d("PermissionsResult", "Grant Results: ${grantResults.joinToString()}")
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onResume() {
|
||||||
|
super.onResume()
|
||||||
|
}
|
||||||
|
|
||||||
|
// override fun onActivityResult(requestCode: Int, resultCode: Int, @Nullable data: Intent?) {
|
||||||
|
// super.onActivityResult(requestCode, resultCode, data)
|
||||||
|
//
|
||||||
|
// // Process only the response result of the authorization process.
|
||||||
|
// if (requestCode == 1002) {
|
||||||
|
// // Obtain the authorization response result from the intent.
|
||||||
|
// val result: HealthKitAuthResult? = huaweiWatch?.mSettingController?.parseHealthKitAuthResultFromIntent(data)
|
||||||
|
// if (result == null) {
|
||||||
|
// Log.w(huaweiWatch?.TAG, "authorization fail")
|
||||||
|
// return
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// if (result.isSuccess) {
|
||||||
|
// Log.i(huaweiWatch?.TAG, "authorization success")
|
||||||
|
// if (result.getAuthAccount() != null && result.authAccount.authorizedScopes != null) {
|
||||||
|
// val authorizedScopes: MutableSet<Scope?> = result.authAccount.authorizedScopes
|
||||||
|
// if(authorizedScopes.isNotEmpty()) {
|
||||||
|
// huaweiWatch?.getHealthAppAuthorization()
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// } else {
|
||||||
|
// Log.w("MainActivty", "authorization fail, errorCode:" + result.getErrorCode())
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
}
|
||||||
@ -0,0 +1,60 @@
|
|||||||
|
package com.ejada.hmg
|
||||||
|
|
||||||
|
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 io.flutter.plugin.common.MethodChannel
|
||||||
|
|
||||||
|
class PenguinInPlatformBridge(
|
||||||
|
private var flutterEngine: FlutterEngine,
|
||||||
|
private var mainActivity: MainActivity
|
||||||
|
) {
|
||||||
|
|
||||||
|
private lateinit var channel: MethodChannel
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
private const val CHANNEL = "launch_penguin_ui"
|
||||||
|
}
|
||||||
|
|
||||||
|
@RequiresApi(Build.VERSION_CODES.O)
|
||||||
|
fun create() {
|
||||||
|
// openTok = OpenTok(mainActivity, flutterEngine)
|
||||||
|
channel = MethodChannel(flutterEngine.dartExecutor.binaryMessenger, CHANNEL)
|
||||||
|
channel.setMethodCallHandler { call: MethodCall, result: MethodChannel.Result ->
|
||||||
|
when (call.method) {
|
||||||
|
"launchPenguin" -> {
|
||||||
|
print("the platform channel is being called")
|
||||||
|
|
||||||
|
if (HostNotificationPermissionManager.isNotificationPermissionGranted(mainActivity))
|
||||||
|
else HostNotificationPermissionManager.requestNotificationPermission(mainActivity)
|
||||||
|
HostBgLocationManager.requestLocationBackgroundPermission(mainActivity)
|
||||||
|
HostGpsStateManager.requestLocationPermission(mainActivity)
|
||||||
|
val args = call.arguments as Map<String, Any>?
|
||||||
|
Log.d("TAG", "configureFlutterEngine: $args")
|
||||||
|
println("args")
|
||||||
|
args?.let {
|
||||||
|
PenguinView(
|
||||||
|
mainActivity,
|
||||||
|
100,
|
||||||
|
args,
|
||||||
|
flutterEngine.dartExecutor.binaryMessenger,
|
||||||
|
activity = mainActivity,
|
||||||
|
channel
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
else -> {
|
||||||
|
result.notImplemented()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,139 @@
|
|||||||
|
package com.cloudsolutions.hmg.PermissionManager;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
import android.content.SharedPreferences;
|
||||||
|
import android.os.Handler;
|
||||||
|
import android.os.HandlerThread;
|
||||||
|
|
||||||
|
import java.util.concurrent.Callable;
|
||||||
|
import java.util.concurrent.ExecutionException;
|
||||||
|
import java.util.concurrent.Future;
|
||||||
|
import java.util.concurrent.FutureTask;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This preferences for app level
|
||||||
|
*/
|
||||||
|
|
||||||
|
public class AppPreferences {
|
||||||
|
|
||||||
|
public static final String PREF_NAME = "PenguinINUI_AppPreferences";
|
||||||
|
public static final int MODE = Context.MODE_PRIVATE;
|
||||||
|
|
||||||
|
public static final String campusIdKey = "campusId";
|
||||||
|
|
||||||
|
public static final String LANG = "Lang";
|
||||||
|
|
||||||
|
public static final String settingINFO = "SETTING-INFO";
|
||||||
|
|
||||||
|
public static final String userName = "userName";
|
||||||
|
public static final String passWord = "passWord";
|
||||||
|
|
||||||
|
private static HandlerThread handlerThread;
|
||||||
|
private static Handler handler;
|
||||||
|
|
||||||
|
static {
|
||||||
|
handlerThread = new HandlerThread("PreferencesHandlerThread");
|
||||||
|
handlerThread.start();
|
||||||
|
handler = new Handler(handlerThread.getLooper());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
public static SharedPreferences getPreferences(final Context context) {
|
||||||
|
return context.getSharedPreferences(AppPreferences.PREF_NAME, AppPreferences.MODE);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static SharedPreferences.Editor getEditor(final Context context) {
|
||||||
|
return getPreferences(context).edit();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public static void writeInt(final Context context, final String key, final int value) {
|
||||||
|
handler.post(() -> {
|
||||||
|
SharedPreferences.Editor editor = getEditor(context);
|
||||||
|
editor.putInt(key, value);
|
||||||
|
editor.apply();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public static int readInt(final Context context, final String key, final int defValue) {
|
||||||
|
Callable<Integer> callable = () -> {
|
||||||
|
SharedPreferences preferences = getPreferences(context);
|
||||||
|
return preferences.getInt(key, -1);
|
||||||
|
};
|
||||||
|
|
||||||
|
Future<Integer> future = new FutureTask<>(callable);
|
||||||
|
handler.post((Runnable) future);
|
||||||
|
|
||||||
|
try {
|
||||||
|
return future.get();
|
||||||
|
} catch (InterruptedException | ExecutionException e) {
|
||||||
|
e.printStackTrace(); // Handle the exception appropriately
|
||||||
|
}
|
||||||
|
|
||||||
|
return -1; // Return the default value in case of an error
|
||||||
|
}
|
||||||
|
|
||||||
|
public static int getCampusId(final Context context) {
|
||||||
|
return readInt(context,campusIdKey,-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
public static void writeString(final Context context, final String key, final String value) {
|
||||||
|
handler.post(() -> {
|
||||||
|
SharedPreferences.Editor editor = getEditor(context);
|
||||||
|
editor.putString(key, value);
|
||||||
|
editor.apply();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public static String readString(final Context context, final String key, final String defValue) {
|
||||||
|
Callable<String> callable = () -> {
|
||||||
|
SharedPreferences preferences = getPreferences(context);
|
||||||
|
return preferences.getString(key, defValue);
|
||||||
|
};
|
||||||
|
|
||||||
|
Future<String> future = new FutureTask<>(callable);
|
||||||
|
handler.post((Runnable) future);
|
||||||
|
|
||||||
|
try {
|
||||||
|
return future.get();
|
||||||
|
} catch (InterruptedException | ExecutionException e) {
|
||||||
|
e.printStackTrace(); // Handle the exception appropriately
|
||||||
|
}
|
||||||
|
|
||||||
|
return defValue; // Return the default value in case of an error
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public static void writeBoolean(final Context context, final String key, final boolean value) {
|
||||||
|
handler.post(() -> {
|
||||||
|
SharedPreferences.Editor editor = getEditor(context);
|
||||||
|
editor.putBoolean(key, value);
|
||||||
|
editor.apply();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean readBoolean(final Context context, final String key, final boolean defValue) {
|
||||||
|
Callable<Boolean> callable = () -> {
|
||||||
|
SharedPreferences preferences = getPreferences(context);
|
||||||
|
return preferences.getBoolean(key, defValue);
|
||||||
|
};
|
||||||
|
|
||||||
|
Future<Boolean> future = new FutureTask<>(callable);
|
||||||
|
handler.post((Runnable) future);
|
||||||
|
|
||||||
|
try {
|
||||||
|
return future.get();
|
||||||
|
} catch (InterruptedException | ExecutionException e) {
|
||||||
|
e.printStackTrace(); // Handle the exception appropriately
|
||||||
|
}
|
||||||
|
|
||||||
|
return defValue; // Return the default value in case of an error
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,136 @@
|
|||||||
|
package com.ejada.hmg.PermissionManager;
|
||||||
|
|
||||||
|
import android.Manifest;
|
||||||
|
import android.app.Activity;
|
||||||
|
import android.app.AlertDialog;
|
||||||
|
import android.content.Context;
|
||||||
|
import android.content.Intent;
|
||||||
|
import android.content.pm.PackageManager;
|
||||||
|
import android.net.Uri;
|
||||||
|
import android.provider.Settings;
|
||||||
|
|
||||||
|
import androidx.core.app.ActivityCompat;
|
||||||
|
import androidx.core.content.ContextCompat;
|
||||||
|
|
||||||
|
import com.peng.pennavmap.PlugAndPlaySDK;
|
||||||
|
import com.peng.pennavmap.R;
|
||||||
|
import com.peng.pennavmap.enums.InitializationErrorType;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Manages background location permission requests and handling for the application.
|
||||||
|
*/
|
||||||
|
public class HostBgLocationManager {
|
||||||
|
/**
|
||||||
|
* Request code for background location permission
|
||||||
|
*/
|
||||||
|
public static final int REQUEST_ACCESS_BACKGROUND_LOCATION_CODE = 301;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Request code for navigating to app settings
|
||||||
|
*/
|
||||||
|
private static final int REQUEST_CODE_SETTINGS = 11234;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Alert dialog for denied permissions
|
||||||
|
*/
|
||||||
|
private static AlertDialog deniedAlertDialog;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if the background location permission has been granted.
|
||||||
|
*
|
||||||
|
* @param context the context of the application or activity
|
||||||
|
* @return true if the permission is granted, false otherwise
|
||||||
|
*/
|
||||||
|
|
||||||
|
public static boolean isLocationBackgroundGranted(Context context) {
|
||||||
|
return ContextCompat.checkSelfPermission(context, Manifest.permission.ACCESS_BACKGROUND_LOCATION)
|
||||||
|
== PackageManager.PERMISSION_GRANTED;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Requests the background location permission from the user.
|
||||||
|
*
|
||||||
|
* @param activity the activity from which the request is made
|
||||||
|
*/
|
||||||
|
public static void requestLocationBackgroundPermission(Activity activity) {
|
||||||
|
// Check if the ACCESS_BACKGROUND_LOCATION permission is already granted
|
||||||
|
if (!isLocationBackgroundGranted(activity)) {
|
||||||
|
// Permission is not granted, so request it
|
||||||
|
ActivityCompat.requestPermissions(activity,
|
||||||
|
new String[]{Manifest.permission.ACCESS_BACKGROUND_LOCATION},
|
||||||
|
REQUEST_ACCESS_BACKGROUND_LOCATION_CODE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Displays a dialog prompting the user to grant the background location permission.
|
||||||
|
*
|
||||||
|
* @param activity the activity where the dialog is displayed
|
||||||
|
*/
|
||||||
|
public static void showLocationBackgroundPermission(Activity activity) {
|
||||||
|
AlertDialog alertDialog = new AlertDialog.Builder(activity)
|
||||||
|
.setCancelable(false)
|
||||||
|
.setMessage(activity.getString(R.string.com_penguin_nav_ui_geofence_alert_msg))
|
||||||
|
.setPositiveButton(activity.getString(R.string.com_penguin_nav_ui_go_to_settings), (dialog, which) -> {
|
||||||
|
if (activity.shouldShowRequestPermissionRationale(Manifest.permission.ACCESS_BACKGROUND_LOCATION)) {
|
||||||
|
HostBgLocationManager.requestLocationBackgroundPermission(activity);
|
||||||
|
} else {
|
||||||
|
openAppSettings(activity);
|
||||||
|
}
|
||||||
|
if (dialog != null) {
|
||||||
|
dialog.dismiss();
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.setNegativeButton(activity.getString(R.string.com_penguin_nav_ui_later), (dialog, which) -> {
|
||||||
|
dialog.cancel();
|
||||||
|
})
|
||||||
|
.create();
|
||||||
|
|
||||||
|
alertDialog.show();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handles the scenario where permissions are denied by the user.
|
||||||
|
* Displays a dialog to guide the user to app settings or exit the activity.
|
||||||
|
*
|
||||||
|
* @param activity the activity where the dialog is displayed
|
||||||
|
*/
|
||||||
|
public static synchronized void handlePermissionsDenied(Activity activity) {
|
||||||
|
if (deniedAlertDialog != null && deniedAlertDialog.isShowing()) {
|
||||||
|
deniedAlertDialog.dismiss();
|
||||||
|
}
|
||||||
|
|
||||||
|
AlertDialog.Builder builder = new AlertDialog.Builder(activity);
|
||||||
|
builder.setCancelable(false)
|
||||||
|
.setMessage(activity.getString(R.string.com_penguin_nav_ui_permission_denied_dialog_msg))
|
||||||
|
.setNegativeButton(activity.getString(R.string.com_penguin_nav_ui_cancel), (dialogInterface, i) -> {
|
||||||
|
if (PlugAndPlaySDK.externalPenNavUIDelegate != null) {
|
||||||
|
PlugAndPlaySDK.externalPenNavUIDelegate.onPenNavInitializationError(
|
||||||
|
InitializationErrorType.permissions.getTypeKey(),
|
||||||
|
InitializationErrorType.permissions);
|
||||||
|
}
|
||||||
|
activity.finish();
|
||||||
|
})
|
||||||
|
.setPositiveButton(activity.getString(R.string.com_penguin_nav_ui_go_settings), (dialogInterface, i) -> {
|
||||||
|
dialogInterface.dismiss();
|
||||||
|
openAppSettings(activity);
|
||||||
|
});
|
||||||
|
deniedAlertDialog = builder.create();
|
||||||
|
deniedAlertDialog.show();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Opens the application's settings screen to allow the user to modify permissions.
|
||||||
|
*
|
||||||
|
* @param activity the activity from which the settings screen is launched
|
||||||
|
*/
|
||||||
|
private static void openAppSettings(Activity activity) {
|
||||||
|
Intent intent = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS);
|
||||||
|
Uri uri = Uri.fromParts("package", activity.getPackageName(), null);
|
||||||
|
intent.setData(uri);
|
||||||
|
|
||||||
|
if (intent.resolveActivity(activity.getPackageManager()) != null) {
|
||||||
|
activity.startActivityForResult(intent, REQUEST_CODE_SETTINGS);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,68 @@
|
|||||||
|
package com.ejada.hmg.PermissionManager;
|
||||||
|
|
||||||
|
import android.Manifest;
|
||||||
|
import android.app.Activity;
|
||||||
|
import android.content.Context;
|
||||||
|
import android.content.pm.PackageManager;
|
||||||
|
import android.location.LocationManager;
|
||||||
|
|
||||||
|
import androidx.core.app.ActivityCompat;
|
||||||
|
import androidx.core.content.ContextCompat;
|
||||||
|
|
||||||
|
import com.peng.pennavmap.managers.permissions.managers.BgLocationManager;
|
||||||
|
|
||||||
|
public class HostGpsStateManager {
|
||||||
|
private static final int LOCATION_PERMISSION_REQUEST_CODE = 1;
|
||||||
|
|
||||||
|
|
||||||
|
public boolean checkGPSEnabled(Activity activity) {
|
||||||
|
LocationManager gpsStateManager = (LocationManager) activity.getSystemService(Context.LOCATION_SERVICE);
|
||||||
|
return gpsStateManager.isProviderEnabled(LocationManager.GPS_PROVIDER);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean isGpsGranted(Activity activity) {
|
||||||
|
return BgLocationManager.isLocationBackgroundGranted(activity)
|
||||||
|
|| ContextCompat.checkSelfPermission(
|
||||||
|
activity,
|
||||||
|
Manifest.permission.ACCESS_FINE_LOCATION
|
||||||
|
) == PackageManager.PERMISSION_GRANTED
|
||||||
|
&& ContextCompat.checkSelfPermission(
|
||||||
|
activity,
|
||||||
|
Manifest.permission.ACCESS_COARSE_LOCATION
|
||||||
|
) == PackageManager.PERMISSION_GRANTED;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if the location permission is granted.
|
||||||
|
*
|
||||||
|
* @param activity the Activity context
|
||||||
|
* @return true if permission is granted, false otherwise
|
||||||
|
*/
|
||||||
|
public static boolean isLocationPermissionGranted(Activity activity) {
|
||||||
|
return ContextCompat.checkSelfPermission(
|
||||||
|
activity,
|
||||||
|
Manifest.permission.ACCESS_FINE_LOCATION
|
||||||
|
) == PackageManager.PERMISSION_GRANTED &&
|
||||||
|
ContextCompat.checkSelfPermission(
|
||||||
|
activity,
|
||||||
|
Manifest.permission.ACCESS_COARSE_LOCATION
|
||||||
|
) == PackageManager.PERMISSION_GRANTED;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Requests the location permission.
|
||||||
|
*
|
||||||
|
* @param activity the Activity context
|
||||||
|
*/
|
||||||
|
public static void requestLocationPermission(Activity activity) {
|
||||||
|
ActivityCompat.requestPermissions(
|
||||||
|
activity,
|
||||||
|
new String[]{
|
||||||
|
Manifest.permission.ACCESS_FINE_LOCATION,
|
||||||
|
Manifest.permission.ACCESS_COARSE_LOCATION,
|
||||||
|
},
|
||||||
|
LOCATION_PERMISSION_REQUEST_CODE
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,73 @@
|
|||||||
|
package com.ejada.hmg.PermissionManager;
|
||||||
|
|
||||||
|
import android.app.Activity;
|
||||||
|
import android.content.pm.PackageManager;
|
||||||
|
import android.os.Build;
|
||||||
|
|
||||||
|
import androidx.annotation.NonNull;
|
||||||
|
import androidx.core.app.ActivityCompat;
|
||||||
|
import androidx.core.app.NotificationManagerCompat;
|
||||||
|
|
||||||
|
public class HostNotificationPermissionManager {
|
||||||
|
private static final int REQUEST_NOTIFICATION_PERMISSION = 100;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if the notification permission is granted.
|
||||||
|
*
|
||||||
|
* @return true if the notification permission is granted, false otherwise.
|
||||||
|
*/
|
||||||
|
public static boolean isNotificationPermissionGranted(Activity activity) {
|
||||||
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
|
||||||
|
try {
|
||||||
|
return ActivityCompat.checkSelfPermission(activity, android.Manifest.permission.POST_NOTIFICATIONS)
|
||||||
|
== PackageManager.PERMISSION_GRANTED;
|
||||||
|
} catch (Exception e) {
|
||||||
|
// Handle cases where the API is unavailable
|
||||||
|
e.printStackTrace();
|
||||||
|
return NotificationManagerCompat.from(activity).areNotificationsEnabled();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Permissions were not required below Android 13 for notifications
|
||||||
|
return NotificationManagerCompat.from(activity).areNotificationsEnabled();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Requests the notification permission.
|
||||||
|
*/
|
||||||
|
public static void requestNotificationPermission(Activity activity) {
|
||||||
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
|
||||||
|
if (!isNotificationPermissionGranted(activity)) {
|
||||||
|
ActivityCompat.requestPermissions(activity,
|
||||||
|
new String[]{android.Manifest.permission.POST_NOTIFICATIONS},
|
||||||
|
REQUEST_NOTIFICATION_PERMISSION);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handles the result of the permission request.
|
||||||
|
*
|
||||||
|
* @param requestCode The request code passed in requestPermissions().
|
||||||
|
* @param permissions The requested permissions.
|
||||||
|
* @param grantResults The grant results for the corresponding permissions.
|
||||||
|
*/
|
||||||
|
public static boolean handlePermissionResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
|
||||||
|
if (permissions.length > 0 &&
|
||||||
|
permissions[0].equals(android.Manifest.permission.POST_NOTIFICATIONS) &&
|
||||||
|
grantResults.length > 0 &&
|
||||||
|
grantResults[0] == PackageManager.PERMISSION_GRANTED) {
|
||||||
|
// Permission granted
|
||||||
|
System.out.println("Notification permission granted.");
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
// Permission denied
|
||||||
|
System.out.println("Notification permission denied.");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,27 @@
|
|||||||
|
package com.ejada.hmg.PermissionManager
|
||||||
|
|
||||||
|
import android.Manifest
|
||||||
|
|
||||||
|
object PermissionHelper {
|
||||||
|
|
||||||
|
fun getRequiredPermissions(): Array<String> {
|
||||||
|
val permissions = mutableListOf(
|
||||||
|
Manifest.permission.INTERNET,
|
||||||
|
Manifest.permission.ACCESS_FINE_LOCATION,
|
||||||
|
Manifest.permission.ACCESS_COARSE_LOCATION,
|
||||||
|
Manifest.permission.ACCESS_NETWORK_STATE,
|
||||||
|
Manifest.permission.BLUETOOTH,
|
||||||
|
Manifest.permission.BLUETOOTH_ADMIN,
|
||||||
|
// Manifest.permission.ACTIVITY_RECOGNITION
|
||||||
|
)
|
||||||
|
|
||||||
|
// For Android 12 (API level 31) and above, add specific permissions
|
||||||
|
// if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) { // Android 12 (API 31) and above
|
||||||
|
permissions.add(Manifest.permission.BLUETOOTH_SCAN)
|
||||||
|
permissions.add(Manifest.permission.BLUETOOTH_CONNECT)
|
||||||
|
permissions.add(Manifest.permission.HIGH_SAMPLING_RATE_SENSORS)
|
||||||
|
// }
|
||||||
|
|
||||||
|
return permissions.toTypedArray()
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,50 @@
|
|||||||
|
package com.ejada.hmg.PermissionManager
|
||||||
|
|
||||||
|
import android.app.Activity
|
||||||
|
import android.content.Context
|
||||||
|
import android.content.pm.PackageManager
|
||||||
|
import android.os.Build
|
||||||
|
import androidx.core.app.ActivityCompat
|
||||||
|
import androidx.core.content.ContextCompat
|
||||||
|
|
||||||
|
class PermissionManager(
|
||||||
|
private val context: Context,
|
||||||
|
val listener: PermissionListener,
|
||||||
|
private val requestCode: Int,
|
||||||
|
vararg permissions: String
|
||||||
|
) {
|
||||||
|
|
||||||
|
private val permissionsArray = permissions
|
||||||
|
|
||||||
|
interface PermissionListener {
|
||||||
|
fun onPermissionGranted()
|
||||||
|
fun onPermissionDenied()
|
||||||
|
}
|
||||||
|
|
||||||
|
fun arePermissionsGranted(): Boolean {
|
||||||
|
return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
|
||||||
|
permissionsArray.all {
|
||||||
|
ContextCompat.checkSelfPermission(context, it) == PackageManager.PERMISSION_GRANTED
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun requestPermissions(activity: Activity) {
|
||||||
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
|
||||||
|
ActivityCompat.requestPermissions(activity, permissionsArray, requestCode)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun handlePermissionsResult(requestCode: Int, permissions: Array<out String>, grantResults: IntArray) {
|
||||||
|
if (this.requestCode == requestCode) {
|
||||||
|
val allGranted = grantResults.all { it == PackageManager.PERMISSION_GRANTED }
|
||||||
|
if (allGranted) {
|
||||||
|
listener.onPermissionGranted()
|
||||||
|
} else {
|
||||||
|
listener.onPermissionDenied()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,15 @@
|
|||||||
|
package com.ejada.hmg.PermissionManager
|
||||||
|
|
||||||
|
// PermissionResultReceiver.kt
|
||||||
|
import android.content.BroadcastReceiver
|
||||||
|
import android.content.Context
|
||||||
|
import android.content.Intent
|
||||||
|
|
||||||
|
class PermissionResultReceiver(
|
||||||
|
private val callback: (Boolean) -> Unit
|
||||||
|
) : BroadcastReceiver() {
|
||||||
|
override fun onReceive(context: Context?, intent: Intent?) {
|
||||||
|
val granted = intent?.getBooleanExtra("PERMISSION_GRANTED", false) ?: false
|
||||||
|
callback(granted)
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,13 @@
|
|||||||
|
package com.ejada.hmg.penguin
|
||||||
|
|
||||||
|
enum class PenguinMethod {
|
||||||
|
// initializePenguin("initializePenguin"),
|
||||||
|
// configurePenguin("configurePenguin"),
|
||||||
|
// showPenguinUI("showPenguinUI"),
|
||||||
|
// onPenNavUIDismiss("onPenNavUIDismiss"),
|
||||||
|
// onReportIssue("onReportIssue"),
|
||||||
|
// onPenNavSuccess("onPenNavSuccess"),
|
||||||
|
onPenNavInitializationError // onLocationOffCampus("onLocationOffCampus"),
|
||||||
|
// navigateToPOI("navigateToPOI"),
|
||||||
|
// openSharedLocation("openSharedLocation");
|
||||||
|
}
|
||||||
@ -0,0 +1,97 @@
|
|||||||
|
package com.ejada.hmg.penguin
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
import com.google.gson.Gson
|
||||||
|
import com.peng.pennavmap.PlugAndPlaySDK
|
||||||
|
import com.peng.pennavmap.connections.ApiController
|
||||||
|
import com.peng.pennavmap.interfaces.RefIdDelegate
|
||||||
|
import com.peng.pennavmap.models.TokenModel
|
||||||
|
import com.peng.pennavmap.models.postmodels.PostToken
|
||||||
|
import com.peng.pennavmap.utils.AppSharedData
|
||||||
|
import okhttp3.ResponseBody
|
||||||
|
import retrofit2.Call
|
||||||
|
import retrofit2.Callback
|
||||||
|
import retrofit2.Response
|
||||||
|
import android.util.Log
|
||||||
|
|
||||||
|
|
||||||
|
class PenguinNavigator() {
|
||||||
|
|
||||||
|
fun navigateTo(mContext: Context, refID: String, delegate: RefIdDelegate,clientID : String,clientKey : String ) {
|
||||||
|
val postToken = PostToken(clientID, clientKey)
|
||||||
|
getToken(mContext, postToken, object : RefIdDelegate {
|
||||||
|
override fun onRefByIDSuccess(PoiId: String?) {
|
||||||
|
Log.e("navigateTo", "PoiId is+++++++ $refID")
|
||||||
|
|
||||||
|
PlugAndPlaySDK.navigateTo(mContext, refID, object : RefIdDelegate {
|
||||||
|
override fun onRefByIDSuccess(PoiId: String?) {
|
||||||
|
Log.e("navigateTo", "PoiId 2is+++++++ $PoiId")
|
||||||
|
|
||||||
|
delegate.onRefByIDSuccess(refID)
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onGetByRefIDError(error: String?) {
|
||||||
|
delegate.onRefByIDSuccess(error)
|
||||||
|
}
|
||||||
|
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onGetByRefIDError(error: String?) {
|
||||||
|
delegate.onRefByIDSuccess(error)
|
||||||
|
}
|
||||||
|
|
||||||
|
})
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getToken(mContext: Context, postToken: PostToken?, apiTokenCallBack: RefIdDelegate) {
|
||||||
|
try {
|
||||||
|
// Create the API call
|
||||||
|
val purposesCall: Call<ResponseBody> = ApiController.getInstance(mContext)
|
||||||
|
.apiMethods
|
||||||
|
.getToken(postToken)
|
||||||
|
|
||||||
|
// Enqueue the call for asynchronous execution
|
||||||
|
purposesCall.enqueue(object : Callback<ResponseBody?> {
|
||||||
|
override fun onResponse(
|
||||||
|
call: Call<ResponseBody?>,
|
||||||
|
response: Response<ResponseBody?>
|
||||||
|
) {
|
||||||
|
if (response.isSuccessful() && response.body() != null) {
|
||||||
|
try {
|
||||||
|
response.body()?.use { responseBody ->
|
||||||
|
val responseBodyString: String = responseBody.string() // Use `string()` to get the actual response content
|
||||||
|
if (responseBodyString.isNotEmpty()) {
|
||||||
|
val tokenModel = Gson().fromJson(responseBodyString, TokenModel::class.java)
|
||||||
|
if (tokenModel != null && tokenModel.token != null) {
|
||||||
|
AppSharedData.apiToken = tokenModel.token
|
||||||
|
apiTokenCallBack.onRefByIDSuccess(tokenModel.token)
|
||||||
|
} else {
|
||||||
|
apiTokenCallBack.onGetByRefIDError("Failed to parse token model")
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
apiTokenCallBack.onGetByRefIDError("Response body is empty")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (e: Exception) {
|
||||||
|
apiTokenCallBack.onGetByRefIDError("An error occurred: ${e.message}")
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
apiTokenCallBack.onGetByRefIDError("Unsuccessful response: " + response.code())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onFailure(call: Call<ResponseBody?>, t: Throwable) {
|
||||||
|
apiTokenCallBack.onGetByRefIDError(t.message)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
} catch (error: Exception) {
|
||||||
|
apiTokenCallBack.onGetByRefIDError("Exception during API call: $error")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,376 @@
|
|||||||
|
package com.ejada.hmg.penguin
|
||||||
|
|
||||||
|
import android.app.Activity
|
||||||
|
import android.content.Context
|
||||||
|
import android.content.Context.RECEIVER_EXPORTED
|
||||||
|
import android.content.IntentFilter
|
||||||
|
import android.graphics.Color
|
||||||
|
import android.os.Build
|
||||||
|
import android.util.Log
|
||||||
|
import android.view.View
|
||||||
|
import android.view.ViewGroup
|
||||||
|
import android.widget.RelativeLayout
|
||||||
|
import android.widget.Toast
|
||||||
|
import androidx.annotation.RequiresApi
|
||||||
|
import com.ejada.hmg.PermissionManager.PermissionManager
|
||||||
|
import com.ejada.hmg.PermissionManager.PermissionResultReceiver
|
||||||
|
import com.ejada.hmg.MainActivity
|
||||||
|
import com.ejada.hmg.PermissionManager.PermissionHelper
|
||||||
|
import com.peng.pennavmap.PlugAndPlayConfiguration
|
||||||
|
import com.peng.pennavmap.PlugAndPlaySDK
|
||||||
|
import com.peng.pennavmap.enums.InitializationErrorType
|
||||||
|
import com.peng.pennavmap.interfaces.PenNavUIDelegate
|
||||||
|
import com.peng.pennavmap.utils.Languages
|
||||||
|
import io.flutter.plugin.common.BinaryMessenger
|
||||||
|
import io.flutter.plugin.common.MethodCall
|
||||||
|
import io.flutter.plugin.common.MethodChannel
|
||||||
|
import io.flutter.plugin.platform.PlatformView
|
||||||
|
import com.peng.pennavmap.interfaces.PIEventsDelegate
|
||||||
|
import com.peng.pennavmap.interfaces.PILocationDelegate
|
||||||
|
import com.peng.pennavmap.interfaces.RefIdDelegate
|
||||||
|
import com.peng.pennavmap.models.LocationMessage
|
||||||
|
import com.peng.pennavmap.models.PIReportIssue
|
||||||
|
import java.util.ArrayList
|
||||||
|
import penguin.com.pennav.renderer.PIRendererSettings
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Custom PlatformView for displaying Penguin UI components within a Flutter app.
|
||||||
|
* Implements `PlatformView` for rendering the view, `MethodChannel.MethodCallHandler` for handling method calls,
|
||||||
|
* and `PenNavUIDelegate` for handling SDK events.
|
||||||
|
*/
|
||||||
|
@RequiresApi(Build.VERSION_CODES.O)
|
||||||
|
internal class PenguinView(
|
||||||
|
context: Context,
|
||||||
|
id: Int,
|
||||||
|
val creationParams: Map<String, Any>,
|
||||||
|
messenger: BinaryMessenger,
|
||||||
|
activity: MainActivity,
|
||||||
|
val channel: MethodChannel
|
||||||
|
) : PlatformView, MethodChannel.MethodCallHandler, PenNavUIDelegate, PIEventsDelegate,
|
||||||
|
PILocationDelegate {
|
||||||
|
// The layout for displaying the Penguin UI
|
||||||
|
private val mapLayout: RelativeLayout = RelativeLayout(context)
|
||||||
|
private val _context: Context = context
|
||||||
|
|
||||||
|
private val permissionResultReceiver: PermissionResultReceiver
|
||||||
|
private val permissionIntentFilter = IntentFilter("PERMISSION_RESULT_ACTION")
|
||||||
|
|
||||||
|
private companion object {
|
||||||
|
const val PERMISSIONS_REQUEST_CODE = 1
|
||||||
|
}
|
||||||
|
|
||||||
|
private lateinit var permissionManager: PermissionManager
|
||||||
|
|
||||||
|
// Reference to the main activity
|
||||||
|
private var _activity: Activity = activity
|
||||||
|
|
||||||
|
private lateinit var mContext: Context
|
||||||
|
|
||||||
|
lateinit var navigator: PenguinNavigator
|
||||||
|
|
||||||
|
init {
|
||||||
|
// Set layout parameters for the mapLayout
|
||||||
|
mapLayout.layoutParams = ViewGroup.LayoutParams(
|
||||||
|
ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT
|
||||||
|
)
|
||||||
|
|
||||||
|
mContext = context
|
||||||
|
|
||||||
|
|
||||||
|
permissionResultReceiver = PermissionResultReceiver { granted ->
|
||||||
|
if (granted) {
|
||||||
|
onPermissionsGranted()
|
||||||
|
} else {
|
||||||
|
onPermissionsDenied()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
|
||||||
|
mContext.registerReceiver(
|
||||||
|
permissionResultReceiver,
|
||||||
|
permissionIntentFilter,
|
||||||
|
RECEIVER_EXPORTED
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
mContext.registerReceiver(
|
||||||
|
permissionResultReceiver,
|
||||||
|
permissionIntentFilter,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set the background color of the layout
|
||||||
|
mapLayout.setBackgroundColor(Color.RED)
|
||||||
|
|
||||||
|
permissionManager = PermissionManager(
|
||||||
|
context = mContext,
|
||||||
|
listener = object : PermissionManager.PermissionListener {
|
||||||
|
override fun onPermissionGranted() {
|
||||||
|
// Handle permissions granted
|
||||||
|
onPermissionsGranted()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onPermissionDenied() {
|
||||||
|
// Handle permissions denied
|
||||||
|
onPermissionsDenied()
|
||||||
|
}
|
||||||
|
},
|
||||||
|
requestCode = PERMISSIONS_REQUEST_CODE,
|
||||||
|
PermissionHelper.getRequiredPermissions().get(0)
|
||||||
|
)
|
||||||
|
|
||||||
|
if (!permissionManager.arePermissionsGranted()) {
|
||||||
|
permissionManager.requestPermissions(_activity)
|
||||||
|
} else {
|
||||||
|
// Permissions already granted
|
||||||
|
permissionManager.listener.onPermissionGranted()
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun onPermissionsGranted() {
|
||||||
|
// Handle the actions when permissions are granted
|
||||||
|
Log.d("PermissionsResult", "onPermissionsGranted")
|
||||||
|
// Register the platform view factory for creating custom views
|
||||||
|
|
||||||
|
// Initialize the Penguin SDK
|
||||||
|
initPenguin()
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun onPermissionsDenied() {
|
||||||
|
// Handle the actions when permissions are denied
|
||||||
|
Log.d("PermissionsResult", "onPermissionsDenied")
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the view associated with this PlatformView.
|
||||||
|
*
|
||||||
|
* @return The main view for this PlatformView.
|
||||||
|
*/
|
||||||
|
override fun getView(): View {
|
||||||
|
return mapLayout
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Cleans up resources associated with this PlatformView.
|
||||||
|
*/
|
||||||
|
override fun dispose() {
|
||||||
|
// Cleanup code if needed
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handles method calls from Dart code.
|
||||||
|
*
|
||||||
|
* @param call The method call from Dart.
|
||||||
|
* @param result The result callback to send responses back to Dart.
|
||||||
|
*/
|
||||||
|
override fun onMethodCall(call: MethodCall, result: MethodChannel.Result) {
|
||||||
|
// Handle method calls from Dart code here
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initializes the Penguin SDK with custom configuration and delegates.
|
||||||
|
*/
|
||||||
|
private fun initPenguin() {
|
||||||
|
navigator = PenguinNavigator()
|
||||||
|
// Configure the PlugAndPlaySDK
|
||||||
|
val language = when (creationParams["languageCode"] as String) {
|
||||||
|
"ar" -> Languages.ar
|
||||||
|
"en" -> Languages.en
|
||||||
|
else -> {
|
||||||
|
Languages.en
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// PlugAndPlaySDK.configuration = Builder()
|
||||||
|
// .setClientData(MConstantsDemo.CLIENT_ID, MConstantsDemo.CLIENT_KEY)
|
||||||
|
// .setLanguageID(selectedLanguage)
|
||||||
|
// .setBaseUrl(MConstantsDemo.DATA_URL, MConstantsDemo.POSITION_URL)
|
||||||
|
// .setServiceName(MConstantsDemo.DATA_SERVICE_NAME, MConstantsDemo.POSITION_SERVICE_NAME)
|
||||||
|
// .setUserName(name)
|
||||||
|
// .setSimulationModeEnabled(isSimulation)
|
||||||
|
// .setCustomizeColor(if (MConstantsDemo.APP_COLOR != null) MConstantsDemo.APP_COLOR else "#2CA0AF")
|
||||||
|
// .setEnableBackButton(MConstantsDemo.SHOW_BACK_BUTTON)
|
||||||
|
// .setCampusId(MConstantsDemo.selectedCampusId)
|
||||||
|
//
|
||||||
|
// .setShowUILoader(true)
|
||||||
|
// .build()
|
||||||
|
|
||||||
|
PIRendererSettings.styleUri = "mapbox://styles/rwaid/cm3h30b36007v01qz7ik8a0sk"
|
||||||
|
|
||||||
|
PlugAndPlaySDK.configuration = PlugAndPlayConfiguration.Builder()
|
||||||
|
.setBaseUrl(
|
||||||
|
creationParams["dataURL"] as String,
|
||||||
|
creationParams["positionURL"] as String
|
||||||
|
)
|
||||||
|
.setServiceName(
|
||||||
|
creationParams["dataServiceName"] as String,
|
||||||
|
creationParams["positionServiceName"] as String
|
||||||
|
)
|
||||||
|
.setClientData(
|
||||||
|
creationParams["clientID"] as String,
|
||||||
|
creationParams["clientKey"] as String
|
||||||
|
)
|
||||||
|
.setUserName(creationParams["username"] as String)
|
||||||
|
// .setLanguageID(Languages.en)
|
||||||
|
.setLanguageID(language)
|
||||||
|
.setSimulationModeEnabled(creationParams["isSimulationModeEnabled"] as Boolean)
|
||||||
|
.setEnableBackButton(true)
|
||||||
|
// .setDeepLinkData("deeplink")
|
||||||
|
.setCustomizeColor("#2CA0AF")
|
||||||
|
.setDeepLinkSchema("", "")
|
||||||
|
.setIsEnableReportIssue(true)
|
||||||
|
.setDeepLinkData("")
|
||||||
|
.setEnableSharedLocationCallBack(false)
|
||||||
|
.setShowUILoader(true)
|
||||||
|
.setCampusId(creationParams["projectID"] as Int)
|
||||||
|
.build()
|
||||||
|
|
||||||
|
|
||||||
|
Log.d(
|
||||||
|
"TAG",
|
||||||
|
"initPenguin: ${creationParams["projectID"]}"
|
||||||
|
)
|
||||||
|
|
||||||
|
Log.d(
|
||||||
|
"TAG",
|
||||||
|
"initPenguin: creation param are ${creationParams}"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Set location delegate to handle location updates
|
||||||
|
// PlugAndPlaySDK.setPiLocationDelegate {
|
||||||
|
// Example code to handle location updates
|
||||||
|
// Uncomment and modify as needed
|
||||||
|
// if (location.size() > 0)
|
||||||
|
// Toast.makeText(_context, "Location Info Latitude: ${location[0]}, Longitude: ${location[1]}", Toast.LENGTH_SHORT).show()
|
||||||
|
// }
|
||||||
|
|
||||||
|
// Set events delegate for reporting issues
|
||||||
|
// PlugAndPlaySDK.setPiEventsDelegate(new PIEventsDelegate() {
|
||||||
|
// @Override
|
||||||
|
// public void onReportIssue(PIReportIssue issue) {
|
||||||
|
// Log.e("Issue Reported: ", issue.getReportType());
|
||||||
|
// }
|
||||||
|
// // Implement issue reporting logic here }
|
||||||
|
// @Override
|
||||||
|
// public void onSharedLocation(String link) {
|
||||||
|
// // Implement Shared location logic here
|
||||||
|
// }
|
||||||
|
// })
|
||||||
|
|
||||||
|
// Start the Penguin SDK
|
||||||
|
PlugAndPlaySDK.setPiEventsDelegate(this)
|
||||||
|
PlugAndPlaySDK.setPiLocationDelegate(this)
|
||||||
|
PlugAndPlaySDK.start(mContext, this)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Navigates to the specified reference ID.
|
||||||
|
*
|
||||||
|
* @param refID The reference ID to navigate to.
|
||||||
|
*/
|
||||||
|
fun navigateTo(refID: String) {
|
||||||
|
try {
|
||||||
|
if (refID.isBlank()) {
|
||||||
|
Log.e("navigateTo", "Invalid refID: The reference ID is blank.")
|
||||||
|
}
|
||||||
|
// referenceId = refID
|
||||||
|
navigator.navigateTo(mContext, refID,object : RefIdDelegate {
|
||||||
|
override fun onRefByIDSuccess(PoiId: String?) {
|
||||||
|
Log.e("navigateTo", "PoiId is penguin view+++++++ $PoiId")
|
||||||
|
|
||||||
|
// channelFlutter.invokeMethod(
|
||||||
|
// PenguinMethod.navigateToPOI.name,
|
||||||
|
// "navigateTo Success"
|
||||||
|
// )
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onGetByRefIDError(error: String?) {
|
||||||
|
Log.e("navigateTo", "error is penguin view+++++++ $error")
|
||||||
|
|
||||||
|
// channelFlutter.invokeMethod(
|
||||||
|
// PenguinMethod.navigateToPOI.name,
|
||||||
|
// "navigateTo Failed: Invalid refID"
|
||||||
|
// )
|
||||||
|
}
|
||||||
|
} , creationParams["clientID"] as String, creationParams["clientKey"] as String )
|
||||||
|
|
||||||
|
} catch (e: Exception) {
|
||||||
|
Log.e("navigateTo", "Exception occurred during navigation: ${e.message}", e)
|
||||||
|
// channelFlutter.invokeMethod(
|
||||||
|
// PenguinMethod.navigateToPOI.name,
|
||||||
|
// "Failed: Exception - ${e.message}"
|
||||||
|
// )
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Called when Penguin UI setup is successful.
|
||||||
|
*
|
||||||
|
* @param warningCode Optional warning code received from the SDK.
|
||||||
|
*/
|
||||||
|
override fun onPenNavSuccess(warningCode: String?) {
|
||||||
|
val clinicId = creationParams["clinicID"] as String
|
||||||
|
|
||||||
|
if(clinicId.isEmpty()) return
|
||||||
|
|
||||||
|
navigateTo(clinicId)
|
||||||
|
// navigateTo("3-1")
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Called when there is an initialization error with Penguin UI.
|
||||||
|
*
|
||||||
|
* @param description Description of the error.
|
||||||
|
* @param errorType Type of initialization error.
|
||||||
|
*/
|
||||||
|
override fun onPenNavInitializationError(
|
||||||
|
description: String?,
|
||||||
|
errorType: InitializationErrorType?
|
||||||
|
) {
|
||||||
|
val arguments: Map<String, Any?> = mapOf(
|
||||||
|
"description" to description,
|
||||||
|
"type" to errorType?.name
|
||||||
|
)
|
||||||
|
Log.d(
|
||||||
|
"description",
|
||||||
|
"description : ${description}"
|
||||||
|
)
|
||||||
|
|
||||||
|
channel.invokeMethod(PenguinMethod.onPenNavInitializationError.name, arguments)
|
||||||
|
Toast.makeText(mContext, "Navigation Error: $description", Toast.LENGTH_SHORT).show()
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Called when Penguin UI is dismissed.
|
||||||
|
*/
|
||||||
|
override fun onPenNavUIDismiss() {
|
||||||
|
// Handle UI dismissal if needed
|
||||||
|
try {
|
||||||
|
mContext.unregisterReceiver(permissionResultReceiver)
|
||||||
|
dispose();
|
||||||
|
} catch (e: IllegalArgumentException) {
|
||||||
|
Log.e("PenguinView", "Receiver not registered: $e")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onReportIssue(issue: PIReportIssue?) {
|
||||||
|
TODO("Not yet implemented")
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onSharedLocation(link: String?) {
|
||||||
|
TODO("Not yet implemented")
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onLocationOffCampus(location: ArrayList<Double>?) {
|
||||||
|
TODO("Not yet implemented")
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onLocationMessage(locationMessage: LocationMessage?) {
|
||||||
|
TODO("Not yet implemented")
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,87 @@
|
|||||||
|
package com.ejada.hmg.watch.huawei
|
||||||
|
|
||||||
|
import android.os.Build
|
||||||
|
import android.util.Log
|
||||||
|
import androidx.annotation.RequiresApi
|
||||||
|
import com.ejada.hmg.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.ejada.hmg.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")
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,423 @@
|
|||||||
|
package com.ejada.hmg.watch.samsung_watch
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
import android.os.Build
|
||||||
|
import android.util.Log
|
||||||
|
import androidx.annotation.RequiresApi
|
||||||
|
import com.ejada.hmg.MainActivity
|
||||||
|
import com.ejada.hmg.watch.samsung_watch.model.Vitals
|
||||||
|
import io.flutter.embedding.engine.FlutterEngine
|
||||||
|
import io.flutter.plugin.common.MethodCall
|
||||||
|
import com.samsung.android.sdk.health.data.HealthDataService
|
||||||
|
import com.samsung.android.sdk.health.data.HealthDataStore
|
||||||
|
import com.samsung.android.sdk.health.data.data.AggregatedData
|
||||||
|
import com.samsung.android.sdk.health.data.data.HealthDataPoint
|
||||||
|
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 com.samsung.android.sdk.health.data.response.DataResponse
|
||||||
|
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"
|
||||||
|
|
||||||
|
|
||||||
|
private lateinit var vitals: MutableMap<String, List<Vitals>>
|
||||||
|
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)
|
||||||
|
vitals = mutableMapOf()
|
||||||
|
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.BODY_TEMPERATURE, AccessType.READ),
|
||||||
|
// Permission.of(DataTypes.EXERCISE, AccessType.READ),
|
||||||
|
// Permission.of(DataTypes.SKIN_TEMPERATURE, AccessType.READ),
|
||||||
|
// Permission.of(DataTypes.NUTRITION, AccessType.READ),
|
||||||
|
|
||||||
|
)
|
||||||
|
val typesToTest = listOf(
|
||||||
|
DataTypes.HEART_RATE,
|
||||||
|
DataTypes.STEPS,
|
||||||
|
DataTypes.BLOOD_OXYGEN,
|
||||||
|
DataTypes.ACTIVITY_SUMMARY,
|
||||||
|
DataTypes.SLEEP,
|
||||||
|
DataTypes.BODY_TEMPERATURE,
|
||||||
|
// DataTypes.EXERCISE
|
||||||
|
)
|
||||||
|
|
||||||
|
scope.launch(Dispatchers.IO) {
|
||||||
|
try {
|
||||||
|
var granted = dataStore.getGrantedPermissions(permSet)
|
||||||
|
|
||||||
|
if (granted.containsAll(permSet)) {
|
||||||
|
result.success("Permission Granted")
|
||||||
|
return@launch
|
||||||
|
}
|
||||||
|
|
||||||
|
// for (type in typesToTest) {
|
||||||
|
// try {
|
||||||
|
// val result = dataStore.requestPermissions(
|
||||||
|
// setOf(Permission.of(type, AccessType.READ)),
|
||||||
|
// mainActivity
|
||||||
|
// )
|
||||||
|
// Log.d("PermCheck", "OK: $type and the result is $result")
|
||||||
|
// } catch (e: Exception) {
|
||||||
|
// Log.e("PermCheck", "FAILED: $type -> ${e.message}")
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
granted = dataStore.requestPermissions(permSet, mainActivity)
|
||||||
|
|
||||||
|
if (granted.containsAll(permSet)) {
|
||||||
|
result.success("Permission Granted") // adapt result as needed
|
||||||
|
return@launch
|
||||||
|
}
|
||||||
|
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).minusDays(365)
|
||||||
|
val localTimeFilter = LocalTimeFilter.of(dateTime, LocalDateTime.now())
|
||||||
|
val readRequest = DataTypes.HEART_RATE.readDataRequestBuilder
|
||||||
|
.setLocalTimeFilter(localTimeFilter)
|
||||||
|
.setOrdering(Ordering.DESC)
|
||||||
|
.build()
|
||||||
|
|
||||||
|
scope.launch(Dispatchers.IO) {
|
||||||
|
val heartRateList = dataStore.readData(readRequest).dataList
|
||||||
|
processHeartVital(heartRateList)
|
||||||
|
Log.d("TAG"," the data is ${vitals}")
|
||||||
|
print("the data is ${vitals}")
|
||||||
|
result.success("Data is obtained")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
"getSleepData" -> {
|
||||||
|
val dateTime = LocalDateTime.now().with(LocalTime.MIDNIGHT).minusDays(365)
|
||||||
|
val localTimeFilter = LocalTimeFilter.of(dateTime, LocalDateTime.now())
|
||||||
|
val readRequest = DataTypes.SLEEP.readDataRequestBuilder
|
||||||
|
.setLocalTimeFilter(localTimeFilter)
|
||||||
|
.setOrdering(Ordering.ASC)
|
||||||
|
.build()
|
||||||
|
scope.launch(Dispatchers.IO) {
|
||||||
|
val sleepData = dataStore.readData(readRequest).dataList
|
||||||
|
processSleepVital(sleepData)
|
||||||
|
print("the data is $vitals")
|
||||||
|
Log.d(TAG, "the data is $vitals")
|
||||||
|
result.success("Data is obtained")
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
"steps"->{
|
||||||
|
val dateTime = LocalDateTime.now().with(LocalTime.MIDNIGHT).minusDays(365)
|
||||||
|
val localTimeFilter = LocalTimeFilter.of(dateTime, LocalDateTime.now())
|
||||||
|
val localTimeGroup = LocalTimeGroup.of(LocalTimeGroupUnit.HOURLY, 1)
|
||||||
|
val aggregateRequest = DataType.StepsType.TOTAL.requestBuilder
|
||||||
|
.setLocalTimeFilterWithGroup(localTimeFilter, localTimeGroup)
|
||||||
|
.setOrdering(Ordering.ASC)
|
||||||
|
.build()
|
||||||
|
|
||||||
|
scope.launch(Dispatchers.IO) {
|
||||||
|
val steps = dataStore.aggregateData(aggregateRequest)
|
||||||
|
processStepsCount(steps)
|
||||||
|
print("the data is $vitals")
|
||||||
|
Log.d(TAG, "the data is $vitals")
|
||||||
|
result.success("Data is obtained")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
"activitySummary"->{
|
||||||
|
val dateTime = LocalDateTime.now().with(LocalTime.MIDNIGHT).minusDays(365)
|
||||||
|
val localTimeFilter = LocalTimeFilter.of(dateTime, LocalDateTime.now())
|
||||||
|
val localTimeGroup = LocalTimeGroup.of(LocalTimeGroupUnit.HOURLY, 1)
|
||||||
|
val readRequest = DataType.ActivitySummaryType.TOTAL_ACTIVE_CALORIES_BURNED
|
||||||
|
.requestBuilder
|
||||||
|
.setLocalTimeFilterWithGroup(localTimeFilter, localTimeGroup)
|
||||||
|
.setOrdering(Ordering.DESC)
|
||||||
|
.build()
|
||||||
|
|
||||||
|
scope.launch(Dispatchers.IO) {
|
||||||
|
val activityResult = dataStore.aggregateData(readRequest).dataList
|
||||||
|
processActivity(activityResult)
|
||||||
|
Log.d("TAG"," the data is ${vitals}")
|
||||||
|
print("the data is ${vitals}")
|
||||||
|
result.success("Data is obtained")
|
||||||
|
}
|
||||||
|
|
||||||
|
// val readRequest = DataTypes.EXERCISE.readDataRequestBuilder
|
||||||
|
// .setLocalTimeFilter(localTimeFilter)
|
||||||
|
// .build()
|
||||||
|
//
|
||||||
|
// scope.launch{
|
||||||
|
// try {
|
||||||
|
// val readResult = dataStore.readData(readRequest)
|
||||||
|
// val dataPoints = readResult.dataList
|
||||||
|
//
|
||||||
|
// processActivity(dataPoints)
|
||||||
|
//
|
||||||
|
//
|
||||||
|
// } catch (e: Exception) {
|
||||||
|
// e.printStackTrace()
|
||||||
|
// }
|
||||||
|
// result.success("Data is obtained")
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
|
||||||
|
"bloodOxygen"->{
|
||||||
|
val dateTime = LocalDateTime.now().with(LocalTime.MIDNIGHT).minusDays(365)
|
||||||
|
val localTimeFilter = LocalTimeFilter.of(dateTime, LocalDateTime.now())
|
||||||
|
val readRequest = DataTypes.BLOOD_OXYGEN.readDataRequestBuilder
|
||||||
|
.setLocalTimeFilter(localTimeFilter)
|
||||||
|
.setOrdering(Ordering.DESC)
|
||||||
|
.build()
|
||||||
|
|
||||||
|
scope.launch(Dispatchers.IO) {
|
||||||
|
val bloodOxygenList = dataStore.readData(readRequest).dataList
|
||||||
|
processBloodOxygen(bloodOxygenList)
|
||||||
|
Log.d("TAG"," the data is ${vitals}")
|
||||||
|
print("the data is ${vitals["bloodOxygen"]}")
|
||||||
|
result.success("Data is obtained")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
"bodyTemperature"->{
|
||||||
|
val dateTime = LocalDateTime.now().with(LocalTime.MIDNIGHT).minusDays(365)
|
||||||
|
val localTimeFilter = LocalTimeFilter.of(dateTime, LocalDateTime.now())
|
||||||
|
val readRequest = DataTypes.BODY_TEMPERATURE.readDataRequestBuilder
|
||||||
|
.setLocalTimeFilter(localTimeFilter)
|
||||||
|
.setOrdering(Ordering.DESC)
|
||||||
|
.build()
|
||||||
|
|
||||||
|
scope.launch(Dispatchers.IO) {
|
||||||
|
val bodyTemperatureList = dataStore.readData(readRequest).dataList
|
||||||
|
processBodyTemperature(bodyTemperatureList)
|
||||||
|
Log.d("TAG"," the data is ${vitals}")
|
||||||
|
print("the data is ${vitals["bodyTemperature"]}")
|
||||||
|
result.success("Data is obtained")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
"distance"->{
|
||||||
|
val dateTime = LocalDateTime.now().with(LocalTime.MIDNIGHT).minusDays(365)
|
||||||
|
val localTimeFilter = LocalTimeFilter.of(dateTime, LocalDateTime.now())
|
||||||
|
val localTimeGroup = LocalTimeGroup.of(LocalTimeGroupUnit.HOURLY, 1)
|
||||||
|
val readRequest = DataType.ActivitySummaryType.TOTAL_DISTANCE.requestBuilder
|
||||||
|
.setLocalTimeFilterWithGroup(localTimeFilter, localTimeGroup)
|
||||||
|
.setOrdering(Ordering.DESC)
|
||||||
|
.build()
|
||||||
|
|
||||||
|
scope.launch(Dispatchers.IO) {
|
||||||
|
val activityResult = dataStore.aggregateData(readRequest).dataList
|
||||||
|
processDistance(activityResult)
|
||||||
|
Log.d("TAG"," the data is ${vitals}")
|
||||||
|
print("the data is ${vitals}")
|
||||||
|
result.success("Data is obtained")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
"retrieveData"->{
|
||||||
|
if(vitals.isEmpty()){
|
||||||
|
result.error("NoDataFound", "No Data was obtained", null)
|
||||||
|
return@setMethodCallHandler
|
||||||
|
}
|
||||||
|
result.success("""
|
||||||
|
{
|
||||||
|
"heartRate": ${vitals["heartRate"]},
|
||||||
|
"steps": ${vitals["steps"]},
|
||||||
|
"sleep": ${vitals["sleep"]},
|
||||||
|
"activity": ${vitals["activity"]},
|
||||||
|
"bloodOxygen": ${vitals["bloodOxygen"]},
|
||||||
|
"bodyTemperature": ${vitals["bodyTemperature"]},
|
||||||
|
"distance": ${vitals["distance"]}
|
||||||
|
}
|
||||||
|
""".trimIndent())
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
"closeCoroutineScope"->{
|
||||||
|
destroy()
|
||||||
|
result.success("Coroutine Scope Cancelled")
|
||||||
|
}
|
||||||
|
|
||||||
|
else -> {
|
||||||
|
result.notImplemented()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun CoroutineScope.processDistance(activityResult: List<AggregatedData<Float>>) {
|
||||||
|
vitals["distance"] = mutableListOf()
|
||||||
|
activityResult.forEach { stepData ->
|
||||||
|
val vitalData = Vitals().apply {
|
||||||
|
|
||||||
|
value = stepData.value.toString()
|
||||||
|
timeStamp = stepData.startTime.toString()
|
||||||
|
}
|
||||||
|
(vitals["distance"] as MutableList).add(vitalData)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun CoroutineScope.processBodyTemperature( bodyTemperatureList :List<HealthDataPoint>) {
|
||||||
|
vitals["bodyTemperature"] = mutableListOf()
|
||||||
|
bodyTemperatureList.forEach { stepData ->
|
||||||
|
val vitalData = Vitals().apply {
|
||||||
|
value = stepData.getValue(DataType.BodyTemperatureType.BODY_TEMPERATURE).toString()
|
||||||
|
timeStamp = stepData.endTime.toString()
|
||||||
|
}
|
||||||
|
(vitals["bodyTemperature"] as MutableList).add(vitalData)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun CoroutineScope.processBloodOxygen( bloodOxygenList :List<HealthDataPoint>) {
|
||||||
|
vitals["bloodOxygen"] = mutableListOf()
|
||||||
|
bloodOxygenList.forEach { stepData ->
|
||||||
|
val vitalData = Vitals().apply {
|
||||||
|
value = stepData.getValue(DataType.BloodOxygenType.OXYGEN_SATURATION).toString()
|
||||||
|
timeStamp = stepData.endTime.toString()
|
||||||
|
}
|
||||||
|
(vitals["bloodOxygen"] as MutableList).add(vitalData)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// private fun CoroutineScope.processActivity(activityResult: List<AggregatedData<Float>>) {
|
||||||
|
//
|
||||||
|
// vitals["activity"] = mutableListOf()
|
||||||
|
// activityResult.forEach { stepData ->
|
||||||
|
// val vitalData = Vitals().apply {
|
||||||
|
//
|
||||||
|
// value = stepData.value.toString()
|
||||||
|
// timeStamp = stepData.startTime.toString()
|
||||||
|
// }
|
||||||
|
// (vitals["activity"] as MutableList).add(vitalData)
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
private fun CoroutineScope.processActivity(activityResult: List<AggregatedData<Float>>) {
|
||||||
|
|
||||||
|
vitals["activity"] = mutableListOf()
|
||||||
|
activityResult.forEach { stepData ->
|
||||||
|
val vitalData = Vitals().apply {
|
||||||
|
|
||||||
|
value = stepData.value.toString()
|
||||||
|
timeStamp = stepData.startTime.toString()
|
||||||
|
}
|
||||||
|
(vitals["activity"] as MutableList).add(vitalData)
|
||||||
|
}
|
||||||
|
|
||||||
|
// dataPoints.forEach { dataPoint ->
|
||||||
|
// val sessions = dataPoint.getValue(DataType.ExerciseType.SESSIONS)
|
||||||
|
//
|
||||||
|
// sessions?.forEach { session ->
|
||||||
|
//
|
||||||
|
// val exerciseSessionCalories = session.calories
|
||||||
|
// val vitalData = Vitals().apply {
|
||||||
|
// value = exerciseSessionCalories.toString()
|
||||||
|
// timeStamp = session.startTime.toString()
|
||||||
|
// }
|
||||||
|
// (vitals["activity"] as MutableList).add(vitalData)
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun CoroutineScope.processStepsCount(result: DataResponse<AggregatedData<Long>>) {
|
||||||
|
val stepCount = ArrayList<AggregatedData<Long>>()
|
||||||
|
var totalSteps: Long = 0
|
||||||
|
vitals["steps"] = mutableListOf()
|
||||||
|
result.dataList.forEach { stepData ->
|
||||||
|
val vitalData = Vitals().apply {
|
||||||
|
value = (stepData.value as Long).toString()
|
||||||
|
timeStamp = stepData.startTime.toString()
|
||||||
|
}
|
||||||
|
(vitals["steps"] as MutableList).add(vitalData)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun CoroutineScope.processSleepVital(sleepData: List<HealthDataPoint>) {
|
||||||
|
vitals["sleep"] = mutableListOf()
|
||||||
|
sleepData.forEach {
|
||||||
|
(vitals["sleep"] as MutableList).add(
|
||||||
|
Vitals().apply {
|
||||||
|
timeStamp = it.startTime.toString()
|
||||||
|
value = (it.getValue(DataType.SleepType.DURATION)?.toMillis().toString())
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private suspend fun CoroutineScope.processHeartVital(
|
||||||
|
heartRateList: List<HealthDataPoint>,
|
||||||
|
) {
|
||||||
|
vitals["heartRate"] = mutableListOf()
|
||||||
|
heartRateList.forEach {
|
||||||
|
(vitals["heartRate"] as MutableList).add(processHeartRateData(it))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun processHeartRateData(heartRateData: HealthDataPoint) =
|
||||||
|
Vitals().apply {
|
||||||
|
heartRateData.getValue(DataType.HeartRateType.MAX_HEART_RATE)?.let {
|
||||||
|
value = it.toString()
|
||||||
|
}
|
||||||
|
timeStamp = heartRateData.startTime.toString()
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
fun destroy() {
|
||||||
|
scope.cancel()
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,13 @@
|
|||||||
|
package com.ejada.hmg.watch.samsung_watch.model
|
||||||
|
|
||||||
|
data class Vitals(
|
||||||
|
var value : String = "",
|
||||||
|
var timeStamp :String = ""
|
||||||
|
){
|
||||||
|
override fun toString(): String {
|
||||||
|
return """{
|
||||||
|
"value": "$value",
|
||||||
|
"timeStamp": "$timeStamp"}
|
||||||
|
""".trimIndent()
|
||||||
|
}
|
||||||
|
}
|
||||||
File diff suppressed because one or more lines are too long
@ -0,0 +1,194 @@
|
|||||||
|
{
|
||||||
|
"pins" : [
|
||||||
|
{
|
||||||
|
"identity" : "abseil-cpp-binary",
|
||||||
|
"kind" : "remoteSourceControl",
|
||||||
|
"location" : "https://github.com/google/abseil-cpp-binary.git",
|
||||||
|
"state" : {
|
||||||
|
"revision" : "bbe8b69694d7873315fd3a4ad41efe043e1c07c5",
|
||||||
|
"version" : "1.2024072200.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"identity" : "app-check",
|
||||||
|
"kind" : "remoteSourceControl",
|
||||||
|
"location" : "https://github.com/google/app-check.git",
|
||||||
|
"state" : {
|
||||||
|
"revision" : "3e33dd27dd4c69bd81c7c81fe61d8ccf58846902",
|
||||||
|
"version" : "11.3.1"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"identity" : "dkcamera",
|
||||||
|
"kind" : "remoteSourceControl",
|
||||||
|
"location" : "https://github.com/zhangao0086/DKCamera",
|
||||||
|
"state" : {
|
||||||
|
"branch" : "master",
|
||||||
|
"revision" : "5c691d11014b910aff69f960475d70e65d9dcc96"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"identity" : "dkimagepickercontroller",
|
||||||
|
"kind" : "remoteSourceControl",
|
||||||
|
"location" : "https://github.com/zhangao0086/DKImagePickerController",
|
||||||
|
"state" : {
|
||||||
|
"branch" : "4.3.9",
|
||||||
|
"revision" : "0bdfeacefa308545adde07bef86e349186335915"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"identity" : "dkphotogallery",
|
||||||
|
"kind" : "remoteSourceControl",
|
||||||
|
"location" : "https://github.com/zhangao0086/DKPhotoGallery",
|
||||||
|
"state" : {
|
||||||
|
"branch" : "master",
|
||||||
|
"revision" : "311c1bc7a94f1538f82773a79c84374b12a2ef3d"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"identity" : "firebase-ios-sdk",
|
||||||
|
"kind" : "remoteSourceControl",
|
||||||
|
"location" : "https://github.com/firebase/firebase-ios-sdk",
|
||||||
|
"state" : {
|
||||||
|
"revision" : "fdc352fabaf5916e7faa1f96ad02b1957e93e5a5",
|
||||||
|
"version" : "11.15.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"identity" : "flutterfire",
|
||||||
|
"kind" : "remoteSourceControl",
|
||||||
|
"location" : "https://github.com/firebase/flutterfire",
|
||||||
|
"state" : {
|
||||||
|
"revision" : "dadb0fd27bc9afe4dee4f23326a4a9ba238258ac",
|
||||||
|
"version" : "3.15.2-firebase-core-swift"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"identity" : "google-ads-on-device-conversion-ios-sdk",
|
||||||
|
"kind" : "remoteSourceControl",
|
||||||
|
"location" : "https://github.com/googleads/google-ads-on-device-conversion-ios-sdk",
|
||||||
|
"state" : {
|
||||||
|
"revision" : "a2d0f1f1666de591eb1a811f40b1706f5c63a2ed",
|
||||||
|
"version" : "2.3.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"identity" : "googleappmeasurement",
|
||||||
|
"kind" : "remoteSourceControl",
|
||||||
|
"location" : "https://github.com/google/GoogleAppMeasurement.git",
|
||||||
|
"state" : {
|
||||||
|
"revision" : "45ce435e9406d3c674dd249a042b932bee006f60",
|
||||||
|
"version" : "11.15.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"identity" : "googledatatransport",
|
||||||
|
"kind" : "remoteSourceControl",
|
||||||
|
"location" : "https://github.com/google/GoogleDataTransport.git",
|
||||||
|
"state" : {
|
||||||
|
"revision" : "ba3358d3c3dbae8ef230b58a46b97ad65e84e974",
|
||||||
|
"version" : "10.1.1"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"identity" : "googleutilities",
|
||||||
|
"kind" : "remoteSourceControl",
|
||||||
|
"location" : "https://github.com/google/GoogleUtilities.git",
|
||||||
|
"state" : {
|
||||||
|
"revision" : "9f183ae842be978784f2963a343682e0c46d8fb3",
|
||||||
|
"version" : "8.1.2"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"identity" : "grpc-binary",
|
||||||
|
"kind" : "remoteSourceControl",
|
||||||
|
"location" : "https://github.com/google/grpc-binary.git",
|
||||||
|
"state" : {
|
||||||
|
"revision" : "75b31c842f664a0f46a2e590a570e370249fd8f6",
|
||||||
|
"version" : "1.69.1"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"identity" : "gtm-session-fetcher",
|
||||||
|
"kind" : "remoteSourceControl",
|
||||||
|
"location" : "https://github.com/google/gtm-session-fetcher.git",
|
||||||
|
"state" : {
|
||||||
|
"revision" : "c756a29784521063b6a1202907e2cc47f41b667c",
|
||||||
|
"version" : "4.5.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"identity" : "interop-ios-for-google-sdks",
|
||||||
|
"kind" : "remoteSourceControl",
|
||||||
|
"location" : "https://github.com/google/interop-ios-for-google-sdks.git",
|
||||||
|
"state" : {
|
||||||
|
"revision" : "040d087ac2267d2ddd4cca36c757d1c6a05fdbfe",
|
||||||
|
"version" : "101.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"identity" : "leveldb",
|
||||||
|
"kind" : "remoteSourceControl",
|
||||||
|
"location" : "https://github.com/firebase/leveldb.git",
|
||||||
|
"state" : {
|
||||||
|
"revision" : "a0bc79961d7be727d258d33d5a6b2f1023270ba1",
|
||||||
|
"version" : "1.22.5"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"identity" : "nanopb",
|
||||||
|
"kind" : "remoteSourceControl",
|
||||||
|
"location" : "https://github.com/firebase/nanopb.git",
|
||||||
|
"state" : {
|
||||||
|
"revision" : "3851d94a41890dea16dc3db34caf60e585cb4163",
|
||||||
|
"version" : "2.30910.1"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"identity" : "promises",
|
||||||
|
"kind" : "remoteSourceControl",
|
||||||
|
"location" : "https://github.com/google/promises.git",
|
||||||
|
"state" : {
|
||||||
|
"revision" : "f4a19a3c313dc2616c70bb49d29a799fb16be837",
|
||||||
|
"version" : "2.4.1"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"identity" : "sdwebimage",
|
||||||
|
"kind" : "remoteSourceControl",
|
||||||
|
"location" : "https://github.com/SDWebImage/SDWebImage",
|
||||||
|
"state" : {
|
||||||
|
"revision" : "2de3a496eaf6df9a1312862adcfd54acd73c39c0",
|
||||||
|
"version" : "5.21.7"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"identity" : "swift-protobuf",
|
||||||
|
"kind" : "remoteSourceControl",
|
||||||
|
"location" : "https://github.com/apple/swift-protobuf.git",
|
||||||
|
"state" : {
|
||||||
|
"revision" : "55d7a1cc5666b85c13464aea1c4b4a90feccb4c8",
|
||||||
|
"version" : "1.38.1"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"identity" : "swiftygif",
|
||||||
|
"kind" : "remoteSourceControl",
|
||||||
|
"location" : "https://github.com/kirualex/SwiftyGif.git",
|
||||||
|
"state" : {
|
||||||
|
"revision" : "4430cbc148baa3907651d40562d96325426f409a",
|
||||||
|
"version" : "5.4.5"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"identity" : "tocropviewcontroller",
|
||||||
|
"kind" : "remoteSourceControl",
|
||||||
|
"location" : "https://github.com/TimOliver/TOCropViewController",
|
||||||
|
"state" : {
|
||||||
|
"revision" : "d4a6d8100f4b886fdbc8ae399bf144ff3e9afb7e",
|
||||||
|
"version" : "2.8.0"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"version" : 2
|
||||||
|
}
|
||||||
@ -0,0 +1,194 @@
|
|||||||
|
{
|
||||||
|
"pins" : [
|
||||||
|
{
|
||||||
|
"identity" : "abseil-cpp-binary",
|
||||||
|
"kind" : "remoteSourceControl",
|
||||||
|
"location" : "https://github.com/google/abseil-cpp-binary.git",
|
||||||
|
"state" : {
|
||||||
|
"revision" : "bbe8b69694d7873315fd3a4ad41efe043e1c07c5",
|
||||||
|
"version" : "1.2024072200.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"identity" : "app-check",
|
||||||
|
"kind" : "remoteSourceControl",
|
||||||
|
"location" : "https://github.com/google/app-check.git",
|
||||||
|
"state" : {
|
||||||
|
"revision" : "3e33dd27dd4c69bd81c7c81fe61d8ccf58846902",
|
||||||
|
"version" : "11.3.1"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"identity" : "dkcamera",
|
||||||
|
"kind" : "remoteSourceControl",
|
||||||
|
"location" : "https://github.com/zhangao0086/DKCamera",
|
||||||
|
"state" : {
|
||||||
|
"branch" : "master",
|
||||||
|
"revision" : "5c691d11014b910aff69f960475d70e65d9dcc96"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"identity" : "dkimagepickercontroller",
|
||||||
|
"kind" : "remoteSourceControl",
|
||||||
|
"location" : "https://github.com/zhangao0086/DKImagePickerController",
|
||||||
|
"state" : {
|
||||||
|
"branch" : "4.3.9",
|
||||||
|
"revision" : "0bdfeacefa308545adde07bef86e349186335915"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"identity" : "dkphotogallery",
|
||||||
|
"kind" : "remoteSourceControl",
|
||||||
|
"location" : "https://github.com/zhangao0086/DKPhotoGallery",
|
||||||
|
"state" : {
|
||||||
|
"branch" : "master",
|
||||||
|
"revision" : "311c1bc7a94f1538f82773a79c84374b12a2ef3d"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"identity" : "firebase-ios-sdk",
|
||||||
|
"kind" : "remoteSourceControl",
|
||||||
|
"location" : "https://github.com/firebase/firebase-ios-sdk",
|
||||||
|
"state" : {
|
||||||
|
"revision" : "fdc352fabaf5916e7faa1f96ad02b1957e93e5a5",
|
||||||
|
"version" : "11.15.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"identity" : "flutterfire",
|
||||||
|
"kind" : "remoteSourceControl",
|
||||||
|
"location" : "https://github.com/firebase/flutterfire",
|
||||||
|
"state" : {
|
||||||
|
"revision" : "dadb0fd27bc9afe4dee4f23326a4a9ba238258ac",
|
||||||
|
"version" : "3.15.2-firebase-core-swift"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"identity" : "google-ads-on-device-conversion-ios-sdk",
|
||||||
|
"kind" : "remoteSourceControl",
|
||||||
|
"location" : "https://github.com/googleads/google-ads-on-device-conversion-ios-sdk",
|
||||||
|
"state" : {
|
||||||
|
"revision" : "a2d0f1f1666de591eb1a811f40b1706f5c63a2ed",
|
||||||
|
"version" : "2.3.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"identity" : "googleappmeasurement",
|
||||||
|
"kind" : "remoteSourceControl",
|
||||||
|
"location" : "https://github.com/google/GoogleAppMeasurement.git",
|
||||||
|
"state" : {
|
||||||
|
"revision" : "45ce435e9406d3c674dd249a042b932bee006f60",
|
||||||
|
"version" : "11.15.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"identity" : "googledatatransport",
|
||||||
|
"kind" : "remoteSourceControl",
|
||||||
|
"location" : "https://github.com/google/GoogleDataTransport.git",
|
||||||
|
"state" : {
|
||||||
|
"revision" : "ba3358d3c3dbae8ef230b58a46b97ad65e84e974",
|
||||||
|
"version" : "10.1.1"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"identity" : "googleutilities",
|
||||||
|
"kind" : "remoteSourceControl",
|
||||||
|
"location" : "https://github.com/google/GoogleUtilities.git",
|
||||||
|
"state" : {
|
||||||
|
"revision" : "9f183ae842be978784f2963a343682e0c46d8fb3",
|
||||||
|
"version" : "8.1.2"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"identity" : "grpc-binary",
|
||||||
|
"kind" : "remoteSourceControl",
|
||||||
|
"location" : "https://github.com/google/grpc-binary.git",
|
||||||
|
"state" : {
|
||||||
|
"revision" : "75b31c842f664a0f46a2e590a570e370249fd8f6",
|
||||||
|
"version" : "1.69.1"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"identity" : "gtm-session-fetcher",
|
||||||
|
"kind" : "remoteSourceControl",
|
||||||
|
"location" : "https://github.com/google/gtm-session-fetcher.git",
|
||||||
|
"state" : {
|
||||||
|
"revision" : "c756a29784521063b6a1202907e2cc47f41b667c",
|
||||||
|
"version" : "4.5.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"identity" : "interop-ios-for-google-sdks",
|
||||||
|
"kind" : "remoteSourceControl",
|
||||||
|
"location" : "https://github.com/google/interop-ios-for-google-sdks.git",
|
||||||
|
"state" : {
|
||||||
|
"revision" : "040d087ac2267d2ddd4cca36c757d1c6a05fdbfe",
|
||||||
|
"version" : "101.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"identity" : "leveldb",
|
||||||
|
"kind" : "remoteSourceControl",
|
||||||
|
"location" : "https://github.com/firebase/leveldb.git",
|
||||||
|
"state" : {
|
||||||
|
"revision" : "a0bc79961d7be727d258d33d5a6b2f1023270ba1",
|
||||||
|
"version" : "1.22.5"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"identity" : "nanopb",
|
||||||
|
"kind" : "remoteSourceControl",
|
||||||
|
"location" : "https://github.com/firebase/nanopb.git",
|
||||||
|
"state" : {
|
||||||
|
"revision" : "3851d94a41890dea16dc3db34caf60e585cb4163",
|
||||||
|
"version" : "2.30910.1"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"identity" : "promises",
|
||||||
|
"kind" : "remoteSourceControl",
|
||||||
|
"location" : "https://github.com/google/promises.git",
|
||||||
|
"state" : {
|
||||||
|
"revision" : "f4a19a3c313dc2616c70bb49d29a799fb16be837",
|
||||||
|
"version" : "2.4.1"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"identity" : "sdwebimage",
|
||||||
|
"kind" : "remoteSourceControl",
|
||||||
|
"location" : "https://github.com/SDWebImage/SDWebImage",
|
||||||
|
"state" : {
|
||||||
|
"revision" : "2de3a496eaf6df9a1312862adcfd54acd73c39c0",
|
||||||
|
"version" : "5.21.7"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"identity" : "swift-protobuf",
|
||||||
|
"kind" : "remoteSourceControl",
|
||||||
|
"location" : "https://github.com/apple/swift-protobuf.git",
|
||||||
|
"state" : {
|
||||||
|
"revision" : "55d7a1cc5666b85c13464aea1c4b4a90feccb4c8",
|
||||||
|
"version" : "1.38.1"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"identity" : "swiftygif",
|
||||||
|
"kind" : "remoteSourceControl",
|
||||||
|
"location" : "https://github.com/kirualex/SwiftyGif.git",
|
||||||
|
"state" : {
|
||||||
|
"revision" : "4430cbc148baa3907651d40562d96325426f409a",
|
||||||
|
"version" : "5.4.5"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"identity" : "tocropviewcontroller",
|
||||||
|
"kind" : "remoteSourceControl",
|
||||||
|
"location" : "https://github.com/TimOliver/TOCropViewController",
|
||||||
|
"state" : {
|
||||||
|
"revision" : "d4a6d8100f4b886fdbc8ae399bf144ff3e9afb7e",
|
||||||
|
"version" : "2.8.0"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"version" : 2
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue