Google Fit heart rate monitor code : onDataPoint not called - Wear OS Software and Hacking General

I',m trying to read heart rate from MIO FUSE device. when connected via the app, the Mio Go App does not sync data with Google fit. I tried directly pairing the device via bluetooth menu and enabled 'Body Sensor' from google fit app.
Code:
Fitness.SensorsApi.findDataSources(mGoogleApiClient, dataSourceRequest)
.setResultCallback(dataSourcesResultCallback);
returns a data source with name of the device and type "DataType.TYPE_HEART_RATE_BPM" datasource. I use that data source to register a listener to get the data. I used the following code for that.
Code:
SensorRequest request = new SensorRequest.Builder()
.setDataSource( dataSource )
.setDataType( dataType )
.setSamplingRate( 10, TimeUnit.SECONDS )
.build();
Fitness.SensorsApi.add(mGoogleApiClient, request, this)
.setResultCallback(new ResultCallback<Status>() {
@Override
public void onResult(Status status) {
if (status.isSuccess()) {
Log.e(TAG, "SensorApi successfully added");
} else {
Log.e(TAG, "adding status: " + status.getStatusMessage());
}
}
});
This method successfully executes and I get the success result too. But I did not get any callback to
Code:
@Override
public void onDataPoint(DataPoint dataPoint) {
//do stuff
}
Is there anything more I have do before getting the values.
Phone : MOTO X Running on Android M Bluetooth device : Mio Fuse
1) is there an issue on the way I try to get the values?
2) is there any other way (an app) where I can register the device which will push periodical heart rate results to google fit. I tried this app Heart Rate OS2 app but it did not even asked me to pair my device with it. Endomonodo and Sport gear tracker reported the heart rate along with activity but not directly.

Related

[Q] Bundle behaviour

Hello, since I do not have 10 posts I can not post in development related forum.
Anyway, I would like to know how Bundle truly works... On Android 2.2 (HTC Desire) I managed to notice strange behaviour - sometimes a Parcelable object is put in and out of the Bundle without the call to Parcelable.writeToParcel(Parcel,int) nor Parcelable.CREATOR.createFromParcel(Parcel).
Also all the fields of class are recreated, even the ones I want to be forgotten - like reference to Context).
So I assume sometimes Bundle use Parcelable protocol and sometimes it simply uses Reflections or even protects a part of memory disallowing it to be collected be garbage collector (Bundle i C++ class wrapper so its highly possible).
My question is: how to handle this strange behaviour?
At this moment I'm doing things like that:
Code:
public class OuterClass
{
[INDENT]protected Context mContext;
protected InnerClass mNoContextData;
protected Parcelable getParcelable()
{
[INDENT]return mNoContextData;[/INDENT]
}
protected void setParcelable(Parcelable aParcelable)
{
[INDENT]mNoContextData = (InnerClass)aParcelable;[/INDENT]
}
public static class InnerClass implements Parcelable
{
[INDENT]//somedata
InnerClass()
{
[INDENT]//data init[/INDENT]
}
//parcelable implementation[/INDENT]
}[/INDENT]
}
I found another strange behavior - android can NOT find class object using above code (InnerClass) when trying to restore object from parcelable after longer time on hold. I get BadParcelable exception all the time ;/.

[DEV] Acessing IR interface

I just started developing for my new Sony tablet and was curious if I can send IR codes with my own app instead of using the Sony app. Here is what I've achieved so far. Maybe someone finds this information usefull and maybe we can provide further information based on this.
The service kinda works, the callbacks get called, I can read raw commands using learnKey() method and I can get the keys for specific devices using getKeyList() but sending IR pattern or key codes to devices seems not to be working quire right, although the callback gets status OK after sending.
Sony created a DataProvider to share data between the app and the service. Thanks to this fact I queried following URI content://com.sony.nfx.app.irremote.provider/learnt and found all custom learnt codes I added via the Sony app. But even using this exact data doesn't seem to do anything when sending to the device.
Access to IR service is restricted by permission and process so our AndroidManifest.xml should look like this:
Code:
<uses-permission android:name="com.sony.nfx.app.irremoteservice.permission.EXECUTE_SERVICE"/>
<application ... android:process=":remote">
...
</application>
Required AIDL files:
Code:
package com.sony.nfx.app.irremoteservice;
import com.sony.nfx.app.irremoteservice.IUEIControlServiceCallback;
interface IUEIControlService {
int sendKey(int i, int j, int k, byte byte0);
int sendSonyCode(int i, int j, byte byte0, int k, byte byte1);
int sendIRPattern(int i, int j, byte byte0, in byte[] pattern);
int sendStopIRSend(int i);
int getKeyList(int i, int j);
int learnKey(int i);
void registerCallback(IUEIControlServiceCallback callback);
void unregisterCallback(IUEIControlServiceCallback callback);
}
Code:
package com.sony.nfx.app.irremoteservice;
interface IUEIControlServiceCallback {
void onCommandComplete(int i, int j);
void onLearntKey(int i, in byte[] abyte0);
void onGetKeyList(int i, int j, in int[] ai);
}
Basic sample code:
Code:
package ir.remote.android;
import java.util.Arrays;
import android.app.Activity;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.Bundle;
import android.os.IBinder;
import android.os.RemoteException;
import android.util.Log;
import com.sony.nfx.app.irremoteservice.IUEIControlService;
import com.sony.nfx.app.irremoteservice.IUEIControlServiceCallback;
public class RemoteTest extends Activity implements ServiceConnection {
private static final String LOG_TAG = "RemoteTest";
private ServiceBinder serviceBinder = new ServiceBinder();
private IUEIControlService remoteService = null;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
String serviceAction = IUEIControlService.class.getName();
Intent serviceIntent = new Intent(serviceAction);
bindService(serviceIntent, this, Context.BIND_AUTO_CREATE);
}
public void onServiceConnected(ComponentName name, IBinder service) {
try {
Log.d(LOG_TAG, "Service connected!");
remoteService = IUEIControlService.Stub.asInterface(service);
remoteService.registerCallback(serviceBinder);
} catch (Exception e) {
Log.e(LOG_TAG, "Error connecting to service!", e);
}
}
public void onServiceDisconnected(ComponentName name) {
Log.d(LOG_TAG, "Service disconnected!");
remoteService = null;
}
public static class ServiceBinder extends IUEIControlServiceCallback.Stub {
public void onCommandComplete(int i, int j) throws RemoteException {
Log.d(LOG_TAG, "onCommandComplete(" + i + ", " + j + ")");
}
public void onGetKeyList(int i, int j, int[] ai) throws RemoteException {
Log.d(LOG_TAG, "onGetKeyList(" + i + ", " + j + ", " + Arrays.toString(ai) + ")");
}
public void onLearntKey(int key, byte[] value) throws RemoteException {
Log.d(LOG_TAG, "onLearntKey(" + key + ", " + Arrays.toString(value) + ")");
}
}
}
Good start
I'm really glad to see someone working on accessing the IR interface. The IR is the primary differentiator that made me decide to buy the Sony Tablet S. I haven't got it yet though, getting it on Monday evening.
I'm only a noob at development, but have started learning Android dev and the start you've made is bound to help. So thanks a lot.
I look forward to seeing your progress.
Luke
Hello Peacemaker2000,
I'm quite new to programing on android (and in java for that matter) so, sorry for the noob questions here.
I have just received my sony tablet last week-end and I think building a custom remote to my needs would be a great hands on exercice
Also I'm a bit disapointed by the natif app which doe not support macro nor look customizaton.
I have tried to start working with all your samples and code to see what I can get to work, but my first concern is about the AIDL files, how do you import the "com.sony.nfx.app.irremoteservice.IUEIControlServiceCallback" ?
The only file that i have found on my tablet, in a "framewok" folder somewhere is "com.sony.nfx.app.irremoteserviceif.jar", I have tried to referenced it by adding to the build path but it is as far as I have been for now.
Any more help / explanation would be greatly appreciated !
Thanks,
Tom.
Good Job Peacemaker,
Main reason i bought it is universal remote control (of course i m an android fan also). If you think that you have to pay 2000$ for a philips pronto remote, SONY did a good start. I am waiting for a customized remote software so to be able to add new buttons, keys etc.
Thank you,
Chris
+1 for me. the ability to have a custom layed out remote with macros and such, I would buy that app.
I ASSUME you have signed up for the sony developers kit they just released, I dl'd it but don't have the time to get into development currently.
Alan
I did subscripbe and download the sdk but only found samples / references for the largescreen / dualscreen layout of the 2 sony tablets, nothing related to the IR.
I did look in to doing something with the IR blaster but couldn't find anything about how to access it. I might start digging around to build the app I was thinking of in my time off over Christmas
Hello to everybody and i wish you a Happy New Year!!!!!!!!!
Any news about IR?
I wonder who will make a new software remote control more customizable, with macros, buttons etc.
Chris
Athens GREECE
I agree with everyone so far about wanting a better app than the remote control one supplied by Sony. I tried learning a macro from my PDA with its universal remote control app, but it refused to learn it. It was OK with single key presses, indeed it is very sensitive.
I bought the Tablet S for my wife, simply because of the eBook reader capability amongst other things but also as a trial for a new replacement universal remote control. This is the first device for ages to have an IR facility built in. I use an old HP Jornada but the screen is mis-behaving after around 10 years of hard labour as a Universal Remote Control. I have found the ability to program my own designed GUI for my numerous cinema, TV etc. devices has been excellent. The Tablet S app is OK in that it has enough keys to cover most remotes. The facility to be able to re-label the keys and choose which of the icons can be which keys is good. It is slightly limited as most of the icons on the left hand panel are fixed labels. Therefore it could be improved.
I would support anyone writing such an app. I would even pay for it! Now that's novel..... Good luck developers.
Thank you so much Peacemaker2000 for sharing your code and ideas.
It works like a charm getting the keys from a remote control and using the data for your own app. I would really like to know what kind of parameters you have to send to get a full keylist of a TV.
Right now I'm just saving the key data from my remote control and don't have any clues how to generally get all possible keys my TV understands. Would be great if you or anybody else who knows this, could share it with us.
If anybody would like to have a functional piece of code from my current prototype, just let me know, right now I have no problems of controlling my Sony Bravia KDL-32W4000.
Perhaps a Mystery Gift app could be developed for use with pokemon gold on a gameboy colour, those were the days
Seems to be quite easy to get a keylist from the actual service:
Code:
int REMOTE_TYPE_ID_KDL_32W4000 = 508;
remoteService.getKeyList(0, REMOTE_TYPE_ID_KDL_32W4000);
You'll get the list in IUEIControlServiceCallback.Stub.onGetKeyList() and execute the appropriate key with:
Code:
int REMOTE_TYPE_ID_KDL_32W4000 = 508;
int ON_OFF_KEY = 18;
remoteService.sendKey(0, REMOTE_TYPE_ID_KDL_32W4000, ON_OFF_KEY, (byte) 0);
remoteService.sendStopIRSend(0);
There you go, TV goes on and off.
I will donate to anyone developing better IR control app.
It will put all that smart LCD screen remotes that they are selling for $1000 and more out of existence.
There is an example of really good IR remote control application. Extremely feature rich. It is called RemoteControl II from http://wincesoft.de/html/remotecontrol_ii.html.
It is only available for Windows CE/Mobile devices.
open source project
hi all, it could be nice to start an open source project, so everyone can collaborate. like me.
david8 said:
hi all, it could be nice to start an open source project, so everyone can collaborate. like me.
Click to expand...
Click to collapse
I've just whipped up a quick Git repo now. Here's the link: https://github.com/agc93/Tablet-S-IR-Control
It'll only be empty atm, because I'm a bit busy at work, but if anyone wants to give it a try, feel free!
agc93 said:
I've just whipped up a quick Git repo now. Here's the link: https://github.com/agc93/Tablet-S-IR-Control
It'll only be empty atm, because I'm a bit busy at work, but if anyone wants to give it a try, feel free!
Click to expand...
Click to collapse
Great! It's a good beginning.
Hi,
I'm an Android beginner developer.
I recently bought a Sony Tablet S and trying to create my own IR Remote App...why?
Sony default IR Remote App don't provides macros.
Here are the main features i'm thiking about:
A dialog box popup automatically when tablet is removed from his dock and shaked...this is managed by a local service)
This dialog provides two options : 1) Default usage of the tablet or 2) Launch my own IR Remote App
This custom App provides only 2 macros : 1) Listen to music or 2) Watch TV
Main challenges i'm facing (as you can easily imagine) is the IR interface implementation.
There's not much code sample on the web, probably because Sony Tablet S is the only device on the market embedding IR interface.
Here are my questions :
Do some one has successfully experienced this technology ?
Is it necessary to root the device before coding with IR interface ?
Do Sony provides specific library to access to IR interface ?
I suppose that each device that i want to remote control (Denon amplifier AVR-2311 and DVico Tvix 6600n for music listening) has an Infrared Hex Code. How do i use it in my classes ?
Waiting for your help
Regards
I for one am very interested in any application that comes close to a Philips Pronto in respect of functionality. The ability to design your own buttons and layouts as wll as have macros is all that is missing from the sony software and I'm sure its possible.
My Pronto is over 10 years old now and one of the reasons for purchasing the Tablet s was as a replacement.
Have a look at the pronto forums on remotecentral.com theres a vast array of downloads of layouts for Pronto edit and hence the hex codes which can be extracted. Many include discrete codes that can't be learned from remotes and are invaluable for macros.
You can also obtain the original editing software and load onto a virtual pronto. If you can produce an ap anything like that then I think you're onto a winner.
Apologies I'm unable to assist on a coding front as I'm a bit of a technonumpty.
Another very confused developer here trying to work out how Sony's bizarre remote calls function. To be honest, not having much luck, and Sony won't help.
If anyone knows how to get it going, please share, because that's all thats stopping me at the moment.
I already posted a working example for sending an IR signal with the tablet. ;-)
I'm also working on an own app with makro-capabilities, custom button layouting (own text, pictures, size, placement) and even custom gestures. I think I can give out a demo in about two weeks, so be a little bit more patient. ;-)
Of course the app will only work with the Tablet S.

[Q] Android delay check for update recursive

I believe I might be attacking this problem with the wrong method or I'm not correctly coding it. I getting to many calls for an update. Sometimes I get update check several in hour. This function is my update function that calls to check for an update every so often unless there no internet and delays and tries again four hours. I don't know if I'm going about this right using a delay? I need for the update function to check and recheck every 24 hours regardless if it finds an update or not. It must try every 24 hours unless it doesn't have internet on the 24th hour and should try again in 4 hours. Am doing this correctly?
Code:
private final Runnable mUpdateUI = new Runnable()
{
public void run()
{
if (isNetworkAvailable()== true)
{
try
{
new checkupdate().execute();
mHandler.postDelayed(mUpdateUI, 86400000);
Toast.makeText(MainActivity.this, "Daily update check!", Toast.LENGTH_LONG).show();
}
catch (IOException e)
{
// TODO Auto-generated catch block
e.printStackTrace();
}
}
else
{
mHandler.postDelayed(mUpdateUI, 21600000);
Toast.makeText(MainActivity.this, "No internet for Daily update check, try again in little!", Toast.LENGTH_LONG).show();
}
}
}
;

[Q] Libgdx and Admob

Hello everybody,
I am a new developer and started with Libgdx to make a simple game (Flappy Bird) an understand everything.
My English is not the best but I could understand this tutorial (tutorial) and make my "own" Flappy Bird.
To complete the tutorial I wanted to show some ads in the app but it didn't work. I used the ads from admob.
Can someone explain me how I can show ads? I think libgdx is the problem but I don't know what I did wrong.
I found this code but it doesn't work and I am getting a few errors: (Is ist correct and am I right if I do in the Android folder a new class
called BannerExample and put this code in it?
import com.google.ads.*;
public class BannerExample extends Activity {
private AdView adView;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
// Create the adView
adView = new AdView(this, AdSize.BANNER, MY_AD_UNIT_ID);
// Lookup your LinearLayout assuming it's been given
// the attribute android:id="@+id/mainLayout"
LinearLayout layout = (LinearLayout)findViewById(R.id.mainLayout);
// Add the adView to it
layout.addView(adView);
// Initiate a generic request to load it with an ad
adView.loadAd(new AdRequest());
}
@Override
public void onDestroy() {
if (adView != null) {
adView.destroy();
}
super.onDestroy();
}
}
Click to expand...
Click to collapse
PS: Sorry for my bad English!
libGDX and AdMob
Hi,
which error messages do you get?
Which Version of libGDX do you use?
I'm not sure if it's possible make it with a class like your BannerExample.
For my app I put all the code for the ad in the AndroidLauncher class.
Additionally you should update to Google Mobile Ads because Google will stop the support of the old standalone sdk.
I think this will help you:
The Article "Google Mobile Ads in Libgdx (replaces deprecated AdMob)" in the libGDX Wiki on github.
And a sample code from "TheInvader360" on github.
I hope you find the right sites. I can't post links .
Good luck

Create a Beautiful Site Tracker App with Huawei Mobile Services (HMS)

More information like this, you can visit HUAWEI Developer Forum​
Original link: https://forums.developer.huawei.com/forumPortal/en/topicview?tid=0201333021967420023&fid=0101187876626530001
HMS DEVELOPMENT
Create a Beautiful Site Tracker App with Huawei Mobile Services (HMS)
Let the friendly war begins.
Hello to you all. As you know, there is an ongoing legal battle between Google i.e USA and Huawei. And things are getting serious in the tech field as well. As you may have heard, Huawei stopped using Google Mobile Services (GMS) from a while on their mobile devices and developed its own Mobile Services which known as Huawei Mobile Services (HMS). It has all the abilities that GMS has except some minor features but those would be implemented in the near future thanks to its robust roadmap of Huawei Core team. And plus, you would get the unique features that only supported by the Huawei ecosystem and its devices. If you have GMS experience somehow, the implementation of HMS would be a piece of cake for you due to its API design is identical to GMS.
Actually, you might want to use HMS Core Toolkit Plugin for those who have GMS implementations on their apps and implement HMS with less effort and pretty UI ?. It has a Convertor feature that automatically changes all GMS package name occurrences with correct HMS mappings. This little Android Studio plugin would save you time rather than some manual labor. And also, it offers a couple of features that would make your HMS development more convenient. But this is up to you.
The number of Huawei Mobile Services aka HMS samples and articles are getting bigger and bigger each day goes by. You could find numerous samples easily and implement them into your app without effort. Different HMS articles release almost in a day such as JavaScript libraries so you will have a lot of options to choose from . So enough chit chat, let’s get into the business.
In this article, I’m gonna show you how to build a site tracker app using Huawei Mobile Services (HMS). Much precisely tracker app for health institutions who do Coronavirus testing in Turkey. For that, we‘re going to use the list of institutions provided by the Minister of Health of Turkey’s website. I named the app COVID19HIT. I know, it does not sound nice but it stands for COVID-19 Health Institutions Tracker. That was the best and simple naming I could get for an app like this one. Apparently, I’m not good at naming apps . Anyways, Before getting into the development, I would like to clarify things beforehand such as the app‘s aim, capabilities, and limitations. I would leave you with concise text that I used in my README file to answer those questions.
It’s an Android sample application that uses Huawei Mobile Services (HMS) to display and search health institutions around you that supports Coronavirus testing in Turkey. The default search radius is 10 km.
The project aims to how to use HMS in real-life applications. Our use-case is displaying all the near health institutions around you that have a certificate to test for Coronavirus. The list itself declared on the website of the Ministry of Health of Turkey. You can check the list out at the link below.
The official list of health institutions
We’re going to use Analytics + Map + Location + Site Kits and Directions API to demonstrate their usage in this use-case. The application’s architecture pattern is MVVM with modular project architecture. Currently, the project has 3 modules which are App, Base and Network modules. Their usage and role differ as modules. And lastly, it developed with everyone’s favorite Kotlin Coroutine which is the language level supported feature.
After that huge boring explanation, I’ll give you short brief information about which Kits solve which use-cases for this app. And, you could click the kit name and see what is more they offer.
Analytics Kit sends user events or properties via Analytics Kit
Map Kit provides a visual map to discover what is around you and drawing 2D shapes
Location Kit locates the user’s current location
Site Kit shows nearby health institutions around 10 KM
Directions API gets you directions based on the options that you select which are by walk, by a drive, and by bike options
Development
FYI, for the sake of the article’s goal, I would only focus on the HMS Development parts in the project. And also, you could ask me any other questions that you have in mind in the comments below.
Each HMS Integration requires the same initial steps, to begin with. You could use this link to prepare your app before implementing features into it. Please, don’t skip this part. This is a mandatory phase. HMS Kits will not work as they should be without it.
After you finish your project’s initial steps, we’re ready to rock and roll.
My DI choice for this project would be Koin which I really recommend who codes in Kotlin. It really takes away all of the boilerplate jobs that Dagger brings on the table. Therefore, we start with Koin initialization in our custom application class’s onCreate() method.
Code:
startKoin {
androidLogger()
androidContext([email protected])
modules(appModule + networkModule)
}
Our module dependencies are in the app module’s com.yektasarioglu.covid19hit.di package.
Code:
val appModule = module {
// Data Sources
single { DiskHealthInstitutionDataSource() }
single { RemoteHealthInstitutionDataSource() }
// Repositories
single { HealthInstitutionRepository(get(), get()) }
viewModel { HomeViewModel(get(), get()) }
}
val networkModule = module {
// Data Sources
single { RemoteDirectionDataSource(get()) }
// Repositories
single { DirectionsRepository(get()) }
single {
OkHttpClient().newBuilder()
.addInterceptor(HttpLoggingInterceptor().apply {
level = if (BuildConfig.DEBUG) HttpLoggingInterceptor.Level.BODY else HttpLoggingInterceptor.Level.NONE
})
.connectTimeout(10000, TimeUnit.MILLISECONDS)
.readTimeout(10000, TimeUnit.MILLISECONDS)
.build()
}
// Services
single {
val retrofit = Retrofit.Builder()
.addConverterFactory(GsonConverterFactory.create())
.baseUrl("https://mapapi.cloud.huawei.com/mapApi/")
.client(get())
.build()
retrofit.create(DirectionsService::class.java)
}
}
This app has only two screens Home and Splash. Our entire logic underlies in Home screen. So, we would focus there mostly. Firstly, Map Kit has two ways to display a map i.e container in our app. The first one is using MapView in our XML which I did. Secondly, you could develop with MapFragment way too. This way of using prevents to call onStart(), onStop(), onResume(), onPause(), onDestroy(), onLowMemory(), and onSaveInstanceState(Bundle outState) methods in its Activity due to Fragment is tied to its parent Activity’s lifecycle. But I chose to use MapView rather than MapFragment. So I did call those Map Kit’s lifecycle methods in HomeActivity. You could choose whatever you want based on your needs. Then, we initialize our managers and request to get location updates at HomeActivity’s onCreate() via calling initialize() method of our ViewModel which takes Activity as a parameter.
Code:
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
initializeUIElements()
with (viewModel) {
initialize([email protected])
initializeStyle(theme = currentTheme)
isCoordinateAvailable.observe([email protected], Observer {
viewModel.moveCameraToCurrentLocation()
viewModel.drawCirclePivotalToCurrentLocation()
})
nearbyHealthInstitutionSites.observe([email protected], Observer {
Log.i("HomeActivity", "nearbyHealthInstitutionSites -> $it")
it.forEach { site->
Log.i(TAG, "site's lat and long: ${site.location.lat}, ${site.location.lng}")
viewModel.markTheSite(site = site, distanceText = resources.getString(R.string.distance))
}
viewModel.setOnMarkerClickListener { marker ->
toast("Clicked ${marker.title}")
with (binding.actionsMenu) {
root.visibility = View.VISIBLE
}
}
toast(getString(R.string.scroll_to_see_more))
})
}
mapView = binding.mapView
mapView.onCreate(savedInstanceState)
mapView.getMapAsync(viewModel.getOnMapReadyCallback())
}
As you would notice, we use ViewModel’s OnMapReadyCallback implementation rather than directly implementing it to Activity. In this case, our ViewModel provides the implementation somewhere else. You would see why we do that just below for a couple of reasons.
Code:
fun initialize(activity: Activity) {
initializeManagers(activity)
requestLocationUpdates()
}
We are going to use Manager classes to encapsulate HMS kit implementations and call it in ViewModel. For our previous example above, ViewModel would only call the MapKitManager’s implementation of OnMapReadyCallback. This helps us to hide all the HMS implementation details in its class, enables us to make changes easily and prevents to propagate more code in HomeViewModel. This approach also suits SOLID principles, especially the Single-responsibility principle. I strongly recommend you to learn it if you don’t know what those are.
Code:
private fun initializeManagers(activity: Activity) {
analyticsManager = AnalyticsManager(activity)
locationKitManager = LocationKitManager(activity)
mapKitManager = MapKitManager()
siteKitManager = SiteKitManager(activity, BuildConfig.HMS_API_KEY)
// For testing purposes
analyticsManager?.sendEvent("XX", Bundle().apply {
putString("TestProperty1", "TestValue1")
})
}
If you run the APK. You would see that the app has two different themes which are Light(Default) and Dark. I wanted to display different map styling for Dark Theme. This custom styling feature is supported by Map Kit. You could use this reference to make your own map style. Even, there is handy Huawei style tool that generates JSON style file based on your customization choices.
Code:
private fun requestLocationUpdates() {
locationKitManager?.requestLocationUpdatesWithCallback(
locationRequest = LocationRequest().apply {
interval = 10000L
priority = LocationRequest.PRIORITY_HIGH_ACCURACY
needAddress = true // This let you to reach the current address information.
},
locationCallback = object : LocationCallback() {
override fun onLocationResult(locationResult: LocationResult?) {
if (locationResult != null) {
with(locationResult.lastHWLocation) {
if (!isNearbyHealthInstitutionsFetched.get()) {
if (userLocation?.city == null &&
userLocation?.country == null &&
userLocation?.state == null &&
userLocation?.coordinate == null
) {
userLocation?.city = city
userLocation?.country = countryName
userLocation?.state = state
userLocation?.coordinate = latitude to longitude
isCoordinateAvailable.value = Unit
viewModelScope.launch {
nearbyHealthInstitutionSites.value =
withContext(context = Dispatchers.Default) {
var list = listOf<Site>()
while (list.isEmpty()) {
Log.i(MTAG, "list is empty")
list = getNearbyHealthInstitutions()
}
isNearbyHealthInstitutionsFetched.set(true)
list
} as ArrayList<Site>
}
}
}
if (stepList != null)
rotateCameraToCurrentDirection(locationResult.lastLocation, stepList!!)
}
} else Log.i(MTAG, "locationResult is NULL !!")
}
})
}
requestLocationUpdatesWithCallback() method’s callback result initiates our flow. Whenever the callback first time returns, we fetch our nearby health institutions with filtered fashion.
Code:
private suspend fun getNearbyHealthInstitutions(radius: Meter = DEFAULT_KM_RADIUS): List<Site> {
return CoroutineScope(Dispatchers.IO).async {
val list = getHealthInstitutions()
val filteredList = list?.filter { it.city == userLocation?.state?.toUpperCase() }
val result = suspendCoroutine<List<Site>> { continuation ->
addNearbyHospitals(
radius = radius,
onEnd = { nearbyHealthInstitutions ->
compareHealthInstitutionLists(
officialHealthInstitutions = filteredList!!,
nearbyHealthInstitutions = nearbyHealthInstitutions
).let { found -> continuation.resume(found) }
})
}
[email protected] result
}.await()
}
Code:
getNearbyHealthInstitutions() does all the work. In a basic sense;
Get health institutions
Filter only the exact matching ones with user location’s city
Search nearby hospitals with the help of Site Kit
Compare the filtered list with the result of Site Kit
Code:
private inline fun addNearbyHospitals(radius: Float, crossinline onEnd: (nearbyHealthInstitutions: List<Site>) -> Unit) {
if (siteKitManager == null) return
val nearbyHealthInstitutions = mutableListOf<Site>()
for (i in 1..SiteKitManager.MAX_PAGE_INDEX) {
Log.i(TAG, "i is $i")
if (siteKitManager!!.isInTheRangeOfMaxResult(pageIndex = i, pageSize = 20))
siteKitManager?.searchNearby(
location = Coordinate(
userLocation?.coordinate?.first!!,
userLocation?.coordinate?.second!!
),
radius = radius,
searchLanguage = "en",
locationType = LocationType.HOSPITAL,
pageFilters = i to 20,
searchResultListener = object : SearchResultListener<NearbySearchResponse?> {
override fun onSearchResult(results: NearbySearchResponse?) {
Log.i("TAG", "Total result count is ${results?.totalCount}")
val sites = results!!.sites
if (results.totalCount <= 0 || sites == null || sites.size <= 0)
return
for (site in sites) {
Log.i("TAG", "siteId: ${site.siteId}, name: ${site.name}, distance: ${site.distance} address: ${site.address} \r\n")
}
nearbyHealthInstitutions.addAll(sites)
if (nearbyHealthInstitutions.size == SiteKitManager.MAX_RESULT)
onEnd(nearbyHealthInstitutions)
}
override fun onSearchError(status: SearchStatus) {
Log.i("TAG", "Error : " + status.errorCode + " " + status.errorMessage)
}
}
)
}
}
{
"lightbox_close": "Close",
"lightbox_next": "Next",
"lightbox_previous": "Previous",
"lightbox_error": "The requested content cannot be loaded. Please try again later.",
"lightbox_start_slideshow": "Start slideshow",
"lightbox_stop_slideshow": "Stop slideshow",
"lightbox_full_screen": "Full screen",
"lightbox_thumbnails": "Thumbnails",
"lightbox_download": "Download",
"lightbox_share": "Share",
"lightbox_zoom": "Zoom",
"lightbox_new_window": "New window",
"lightbox_toggle_sidebar": "Toggle sidebar"
}
addNearbyHospitals() returns its result to onEnd(List<Site>) lambda parameter does the post-process after its call. This enable us to get the max result which is 60. We loop until the nearbyHealthInstitutions’ element count is 60. Checking of pageIndex x pageSize ≤ 60 formula under the isInTheRangeOfMaxResult(Int, Int) method.
Then, we compare the nearby hospital list with official health institutions. This comparison’s result is our final list that we would mark it on the map. A comparison algorithm is just a basic token comparison. It uses the Levenshtein distance method to compare two strings. Nowadays, you don’t have to be a math genius to use these methods thanks to StackOverflow. But as an enthusiast, you might go and learn how the Levenshtein distance algorithm works in the first place. Before getting into the next phase, I would like to mention about data fetching layer. Under the hood, the data fetching mechanism designed to get data from a Repository. A repository method returns a result if the data wasn’t cached. Repository Pattern is another good old design pattern that you should learn if you didn’t know. It simplifies the data fetching layer of your app. You should check this link out if you’re interested in. Data collection of the app is not so robust due to the Ministry of Health of Turkey changes its HTML so often . As you would guess, all we do is some basic web scraping. As you were reading, the Ministry of Health of Turkey might change its website’s HTML some of two. And that would lead to corrupt scraped data and cause you to see fewer health institutions or nothing at all. Unfortunately, there is no REST API for getting certified health institutions in Turkey. That is all we have for now I am afraid. If you find a stable REST API for getting certified health institutions in X country. The country does not matter as long as the data is stable, just let me know. Or you could implement it on your own and contribute it to the sample project. I would gladly accept your contribution to the project.
Our last demonstration would be how to navigate to your destination point from your current location. For that, the app only offers a simple display of directions at this moment. No fancy or complex features are supported for the sake of the simplicity of our app’s context. As you would see above, there is a compound component and each component’s action would provide 3 different routes(walking/driving/bicycling). At that point, Directions API would come to rescue from our train of thoughts about how to get directions. Then, these directions would be displayed on the map with drawing polylines till the destination point via MapKit. And that would pretty much do the job in a nutshell.
Bonus Resource
I created also Postman collections for both Directions and Matrix APIs to observe all the endpoints. All you have to do is create an empty project under my projects section in AppGallery Connect. Then use this field as your API Key like the above image to test it.
Code:
fun getRoute(`for`: RouteType, onFailed: ((errorMessage: String) -> Unit)? = null) {
val originCoordinates =
Coordinates(userLocation?.coordinate?.first!!, userLocation?.coordinate?.second!!)
val destinationCoordinates = Coordinates(
mapKitManager?.selectedMarker?.position!!.latitude,
mapKitManager?.selectedMarker?.position!!.longitude
)
val routeDirection =
RouteDirection(origin = originCoordinates, destination = destinationCoordinates)
viewModelScope.launch {
var routeResponse: RouteResponse? = null
when (`for`) {
RouteType.WALK -> {
routeResponse = directionsRepository.getWalkingRoute(routeDirection) {
onFailed?.invoke(it)
}
}
RouteType.DRIVE -> {
routeResponse = directionsRepository.getDrivingRoute(routeDirection) {
onFailed?.invoke(it)
}
}
RouteType.BICYCLE -> {
routeResponse = directionsRepository.getBicyclingRoute(routeDirection) {
onFailed?.invoke(it)
}
}
}
stepList = routeResponse?.routes?.first()?.paths?.first()?.steps
routeResponse?.let {
mapKitManager?.removePolylines()
mapKitManager?.generateRoute(it)
}
}
}
After we fill stepList variable with the response. Our code block in the onLocationResult callback method which is the below would be triggered. This code block below exists in the article as the sixth gist but in the terms of laziness, I made this as another gist. Who likes to scroll up in a long article, right ? As we know, requestLocationUpdatesWithCallback() method’s callback invokes after each x interval. That would cause a rotate camera to the current direction.
Code:
if (stepList != null)
rotateCameraToCurrentDirection(locationResult.lastLocation, stepList!!)
Github Repository
yektasarioglu/covid19hit
That is it for this article. You could search any question that comes to your mind via Huawei Developer Forum. And lastly, you could find lengthy detailed videos at Huawei Developers YouTube channel. These resources diversify learning channels and make things easy to pick and learn from a huge knowledge pool. In short, there is something for everybody in here . Stay tuned for more HMS Development resources. Thanks for reading. Be safe folks.
Nice article
What should I do if error code 6 is returned when I call APIs of Site Kit?
riteshchanchal said:
What should I do if error code 6 is returned when I call APIs of Site Kit?
Click to expand...
Click to collapse
Can you provide the screenshot or the steps you call ?

Categories

Resources